我有一个变量 ,var
其中包含:
XXXX YY ZZZZZ\n
aaa,bbb,ccc
我想要的只是aaa
第二行。我试过:
out=$(echo "$var" | awk 'NR==2{sub(",.*","")}' )
但我没有得到任何输出。我尝试使用,
as FS 但我无法得到正确的语法。我真的很想学习 awk/regex 语法。
我想在其他地方使用 out 作为变量“$out”——而不是打印。
答案1
你不想要正则表达式。整个要点awk
是自动将一行拆分为多个字段,因此只需将字段分隔符设置为,
并打印第二行的第一个字段:
$ printf '%s' "$var" | awk -F, 'NR==2{print $1}'
aaa
或者,如果您的 shell 支持<<<
:
$ awk -F, 'NR==2{print $1}' <<<"$var"
aaa
如果您确实想手动执行而不awk
按预期使用,您可以执行以下操作:
$ awk 'NR==2{sub(/,.*/,""); print}' <<<"$var"
aaa
您没有得到任何输出,因为您没有告诉awk
打印任何内容。
答案2
或者,您也可以在此处使用${param#pattern}
和${param%%pattern}
标准参数扩展运算符:
NL='
'
out=${var#*"$NL"} # removes first line. Assumes there are at least 2
out=${out%%"$NL"*} # removes all but the first line
out=${out%%,*} # removes everything after the first ,
或者bash
具体而言,您可以使用:
LC_ALL=C # needed to accept non-text
[[ $var =~ ^[^$'\n']*$'\n'([^,$'\n']*) ]]
out=${BASH_REMATCH[1]}
标准情况下,还有expr
:
NL='
'
out=$(LC_ALL=C expr "x$var" : "[^$NL]*$NL\([^,$NL]*\)")
您的方法的问题是您没有告诉awk
打印任何内容。如果awk
不打印任何内容,则当$(...)
扩展为内部命令的输出时,变量中不会存储任何内容。另外,请记住echo
不能用于打印任意数据。
out=$(printf '%s\n' "$var" | awk 'NR == 2 {sub(",.*", ""); print}')
或者:
out=$(printf '%s\n' "$var" | awk -F, 'NR == 2 {print $1}')
1 减去尾随换行符,如果输出包含 NUL 字节,则 shell 实现之间的行为会有所不同
答案3
另一种选择使用sed
:
sed -n 's/,.*$//p' <<< "$var"
- 这会将 (
s/../../
) 从每行第一行开始,
到行尾 (,.*$
) 的所有内容替换为“无”,从而仅留下该部分前首先,
。 - 通过使用该
-n
选项,默认情况下会抑制输出。p
程序末尾的 指示仍然sed
打印找到“搜索”模式的行。这样,我们忽略第一行(不带),只处理实际找到,
a 的第二行。,
像往常一样,您可以通过命令替换将结果导入到 shell 变量中:
out=$(sed -n 's/,.*$//p' <<< "$var")
或者,在不理解此处字符串的 shell 中,
out=$(printf '%s' "$var" | sed -n 's/,.*$//p')
请注意,由于您没有包含边缘案例的示例,因此很难设计解决方案来容纳$var
.当前的解决方案假设只有一行带有 a ,
,您要从中提取第一个字段。
答案4
使用sed
:
$ sed -n '2s/,.*//p' <<<"$var"
aaa
特别是如果您正在读取一个大文件,最好在命令执行第二行后设置一个断点。
$ sed -n '2{s/,.*//p;q;}' infile
这将q
有助于稍后对输入文件的处理。