使用 awk 删除“,”后面的所有内容

使用 awk 删除“,”后面的所有内容

我有一个变量 ,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有助于稍后对输入文件的处理。

相关内容