【问题标题】:Extract values from file efficiently有效地从文件中提取值
【发布时间】:2019-07-15 15:00:54
【问题描述】:

假设我有这个文件:version.h

#define MAJ_VERSION         1
#define MIN_VERSION         4
#define BLD_VERSION         0

使用 bash 脚本,如何提取 $maj==1$min==4$bld==0 等 3 个单独变量中的值?

我围绕这个正则表达式尝试了几种方法:s/\_VERSION\s*(\d*)/,它允许我在每行中提取第一个匹配组中的值,但我未能找到一个优雅的解决方案。

例如,这不起作用(还需要一个计数器来消除这 3 个值的歧义):

str=$(cat version.h)
for var in ${str[@]}; do
    echo
    if [[ ${var} =~ (\_VERSION\s*)([0-9]*) ]]; then
        echo "match: '${BASH_REMATCH[1]}'"
        echo "match: '${BASH_REMATCH[2]}'"
    fi
done

【问题讨论】:

  • 要匹配数字,请使用[0-9],而不是\d

标签: regex bash awk sed sh


【解决方案1】:

假设您使用 bash 和 GNU sed:

source <(sed -E 's/.*(MAJ|MIN|BLD)_VERSION[[:blank:]]+(.*)/\L\1="\2"/' version.h)

验证变量内容:

$ declare -p maj min bld
declare -- maj="1"
declare -- min="4"
declare -- bld="0"

【讨论】:

  • 漂亮的单线!如何捕获majminbld 变量?另外,我对此有一个小问题,在某些情况下,version.h 是在 Windows 上生成的并且具有 CRLF 行结尾,我最终得到typeset min=$'4\C-M'。这在执行算术运算(例如$(($maj+1)))时会导致问题。你会怎么处理呢?
  • 对于后者,我会将(.*) 更改为([^\r]*)
  • 对于前者,请考虑我在左侧捕获的内容,以及我在粗糙的一侧替换的内容。然后研究 bash “进程替换”和内置的source 命令。
  • GNU sed \L 小写
  • 您可以尝试sed -E -e 's/\r$//' -e 'my original answer'“预删除”回车。
【解决方案2】:

应该这样做

 maj=$(grep MAJ_VERSION version.h | awk '{print $3}')
 min=$(grep MIN_VERSION version.h | awk '{print $3}')
 bld=$(grep BLD_VERSION version.h | awk '{print $3}')

【讨论】:

  • @Fluffy 好吧,这是最简单的 awk 形式之一。它只是打印出其输入的第三列
  • 6 个进程和 3 个管道并没有完全“有效”地做到这一点!使用 awk 时永远不需要 grep,一个 awk 命令可以一次生成所有值,然后您可以简单地在调用 shell 中读取这些值或保存为数组值
  • @Ed Morton 我刚刚提供了一个非常简单且有效的解决方案。我从来没有声称它是最有效的。我完全同意它可能会更好
  • 我提到效率不是因为你声称的任何东西,而是因为 OP 的问题是如何Extract values from file efficiently
  • 好的,但是我非常想看看有多少源文件变体会破坏我的解决方案,以及有多少变体会破坏您的“更有效”的解决方案。例如,对我来说,一些依赖于输入行的特定顺序来工作的东西,我不会真正称之为“高效”,只是因为它使用了更复杂的 awk..
【解决方案3】:

如果输入文件中的值始终以该顺序存在:

$ read -r maj min bld < <(awk '{printf "%s ", $3} END{print ""}' file)
$ echo "$maj, $min, $bld"
1, 4, 0

如果您在输入文件中显示的行数超过 3 行,则将 awk 调整为:

awk '/^#define.*VERSION/{printf "%s ", $3} END{print ""}' file

如果订单未预定义,则再次调整为:

awk '/^#define.*VERSION/{sub(/_.*/,"",$2); f[$2]=$3} END{print f["MAJ"], f["MIN"], f["BLD"]}' file

如果还有其他问题,请告诉...

【讨论】:

  • 感谢您的详尽输入,我对此有最后一个问题(重复上述评论):在某些情况下,version.h 是在 Windows 上生成的并且具有 CRLF 行结尾,我以 @ 结尾987654324@。这会在执行算术运算(例如 $(($maj+1)))时导致问题。你会怎么处理呢?
  • 在引用 $3 之前添加 sub(/\r/,""),例如{sub(/\r/,""); printf "%s ", $3}.
猜你喜欢
  • 2010-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多