如何在单引号参数中扩展变量?

如何在单引号参数中扩展变量?

我正在尝试执行以下操作,但没有运气:

SORT_BY='-k3,3r -k2,2 -k1,1r'
awk 'NR<4{print $0;next}{print $0 | sort '"${SORT_BY}"' -t"~"}'

我尝试过各种引号、取消引号等,但 awk 上总是有问题

awk: illegal statement

我该如何进行扩展>

答案1

awk 不是 shell。您无法sort直接从 awk 调用 UNIX 工具,就像无法直接从 C 程序调用它们一样。

这将使您想要做的事情发挥作用:

SORT_BY='-k3,3r -k2,2 -k1,1r'
awk 'NR<4{print; next} {print | "sort -t\"~\" '"${SORT_BY}"'"}'

但目前还不清楚这是否是一个好主意。

猜测您想要做的是打印 3 个未排序的标题行,然后对其余数据进行排序,这可能是最好的方法,因为除了设置 awks 输出分隔符并将输入分隔符排序为同一字符之外,它完全解耦awk 从排序中,不需要 awk 生成 shell,并且无论输入来自管道还是文件都可以工作,因为它不需要打开输入两次:

sep='~'
awk -v OFS="$sep" '{print (NR>3), NR, $0}' file |
sort -t "$sep" -k1,1n -k2,2n -k5,5r -k4,4 -k3,3r |
cut -d "$sep" -f3-

答案2

变量不会在单引号字符串中展开。没有办法解决这个问题。

在本例中,您希望按原样输出数据的前三行,并对其余部分进行排序。为了简单起见,我会这样做

sort_opts=( -k3,3r -k2,2 -k1,1r )

{  head -n 3 file
   awk 'NR > 3' file | sort "${sort_opts[@]}" -t '~'  } >newfile

如果您觉得确实想从内部进行排序awk,并假设$IFS保持不变,并将空格作为第一个字符:

sort_opts=( -k3,3r -k2,2 -k1,1r )

awk -v sort_opts="${sort_opts[*]}" '
    BEGIN { sortcmd = sprintf("sort %s -t \"~\"", sort_opts) }
    NR <= 3 { print; next } { print | sortcmd }' file >newfile

这提供了在命令行上awk使用的排序选项,该块创建排序命令以用作变量中的字符串,然后在最后一个块中使用它(从第 4 行开始触发)。-vBEGINsortcmd

print请注意,当与 in 中的管道一起使用时awk,管道的右侧必须是表示要通过管道传输到的 shell 命令的字符串。您的代码中并非如此,这就是您收到“非法声明”错误的原因。


当您需要导入的值awk包含反斜杠时,您可能需要改用环境变量(以避免将每个反斜杠加倍):

sort_opts=( -k3,3r -k2,2 -k1,1r )

SORT_OPTS="$sort_opts[*]" awk '
    BEGIN { sortcmd = sprintf("sort %s -t \"~\"", ENVIRON["SORT_OPTS"]) }
    NR <= 3 { print; next } { print | sortcmd }' file >newfile

相关内容