我觉得这是一个非常简单的问题,当我谷歌时,我找到了部分问题的很多答案,但是当我尝试将它们放在一起时,它不起作用,我不明白为什么。
这是场景:
- 我有一个文件,里面有很多文本。
- 其中一行与此模式匹配:
foo = 1700;
- 我想提取
1700
- 我想将其保存到 bash 脚本变量中,以便稍后在脚本中引用它。
我无法通过第 3 步。这是我尝试过的:
sed -nE 's/^foo = //p' file | sed -nE 's/;//p'
这打印出:
1700
很好,但是如果我需要修剪空白或其他内容怎么办?如果我不能使用*
/ +
,我就不知道该怎么做。我了解到你不能使用*
/+
替换另一个答案,所以我不知道如何做到这一点。我查看了 grep 的手册页,当我搜索该词时,我没有看到任何组选项。我想我知道如何在 awk 中解决这个问题,但我总是发现它的正则表达式函数有点笨拙,并且命令行脚本需要太多转义,所以理想情况下这不是解决这个问题的唯一方法。
答案1
首先,介绍如何捕获数值:
$ echo 'foo = 1700;' | sed -n -e 's/^foo = \([0-9]\+\).*/\1/p' 1700
这是使用
sed
默认的基本正则表达式(BRE)。您还可以将扩展正则表达式 (ERE) 与 sed-E
选项一起使用:echo 'foo = 1700;' | sed -n -E -e 's/^foo = ([0-9]+).*/\1/p' 1700
[0-9]+
括号内的子表达式(
...)
捕获一个或多个数字。这称为“捕获组”,用于替换为\1
(这是第一的捕获组 - 如果有多个捕获组,它们可以用作 \1、\2、\3 等)。在这种情况下,sed 脚本尝试仅使用 \1 捕获组替换整行,如果成功,则打印修改后的行。
接下来,您希望将
sed
的输出放入变量中。你这样做与命令替换。例如$ myvar=$(echo 'foo = 1700;' | sed -n -E -e 's/^foo = ([0-9]+).*/\1/p') $ echo $myvar 1700
要在脚本中使用它,只需使用您的文件作为 sed 的参数,而不是通过管道输入
echo ...
它。myvar=$(sed -n -E -e 's/^foo = ([0-9]+).*/\1/p' file)
修剪空白,或处理可能具有可选前导空白或周围可选空白
=
等的行:myvar=$(sed -n -E -e 's/^[[:space:]]*foo[[:space:]]*=[[:space:]]*([0-9]+).*/\1/p' file)
请注意,某些版本的 sed(至少是 GNU sed,也许其他版本)理解
perl's
\s
,因此您可以将其缩短为:myvar=$(sed -n -E -e 's/^\s*foo\s*=\s*([0-9]+).*/\1/p' file)
答案2
为了完整起见,使用支持和的正则表达式的grep
实现,您可以执行以下操作:-o
perl
-P
grep -Po 'foo\s*=\s*\K\d+'
在哪里:
\s
匹配任何空白字符*
0 个或多个前面的原子。例如\s*
匹配 0 个或多个空白字符。\d
匹配十进制数字(通常与 相同[0123456789]
,但[0-9]
通常不匹配更多字符)。+
匹配一个或多个前面的原子。\K
重置匹配部分的开始(要 eep 的内容,或者在要输出K
的情况下)。grep -o
o
因此,这将打印一个或多个数字的所有序列,后跟foo=
两侧允许的任意数量的空格=
,即使给定行上出现多个数字。
使用pcregrep
,您还可以在后面指定一个数字-o
来打印给定捕获组匹配的内容,而不是整个匹配部分:
pcregrep -o1 'foo\s*=\s*(\d+)'
可移植的是,您实际上可以使用真实的东西perl
::
perl -lne 'print $1 for m{foo\s*=\s*(\d+)}g'
答案3
假设你想挑选一个foo
数值,
echo 'foo = 1700;' | awk '$1=="foo" {print $NF+0}'
1700
默认情况下awk
,按空格拆分(而不仅仅是单个空格)。NF
是字段数,在本例中为 3;$NF
是第 3 个空格字段的字符串值。+0
将此字符串转换1700;
为数值1700
。
它适用于诸如 之类的行,foo = 1700;
但不适用于诸如 之类的行foo=1700;
。从你的问题中我不确定你是否只是关心删除额外的空白,或者你的数据可能没有空白,而 和=
是;
唯一的边界点。如果你想忽略任何空格,无论有没有,你最好使用sed
,
echo 'foo=1700;' | sed -n 's/^foo *= *//p' | sed -e 's/;$//' -e 's/ *$//'
1700
答案4
awk '{for(i=1;i<=NF;i++){if($i ~ /foo/ && $0 ~ /foo.*=.*[0-9]*/){gsub(";","",$(i+2));print $(i+2)}}}' filename
测试并运行良好