【问题标题】:awk command fails with command substitutionawk 命令因命令替换而失败
【发布时间】:2017-07-05 15:49:37
【问题描述】:

运行此命令失败:

$(printf "awk '{%sprint}'" $(tail -n +2 file.txt | cut -f2 | sort | uniq | awk 'BEGIN{a=1}{printf "gsub(\"%s\",%i);", $1,a++}')) file.txt

它给出了以下错误:

awk: '
awk: ^ invalid char ''' in expression

但是,如果我运行替换的命令,我会得到:

awk '{gsub("ACB",1);gsub("ASW",2);gsub("BEB",3);gsub("CDX",4);gsub("CEU",5);gsub("CHB",6);gsub("CHS",7);gsub("CLM",8);gsub("ESN",9);gsub("FIN",10);gsub("GBR",11);gsub("GIH",12);gsub("GWD",13);gsub("IBS",14);gsub("ITU",15);gsub("JPT",16);gsub("KHV",17);gsub("LWK",18);gsub("MSL",19);gsub("MXL",20);gsub("PEL",21);gsub("PJL",22);gsub("PUR",23);gsub("STU",24);gsub("TSI",25);gsub("YRI",26);print}'

我可以这样运行:

awk '{gsub("ACB",1);gsub("ASW",2);gsub("BEB",3);gsub("CDX",4);gsub("CEU",5);gsub("CHB",6);gsub("CHS",7);gsub("CLM",8);gsub("ESN",9);gsub("FIN",10);gsub("GBR",11);gsub("GIH",12);gsub("GWD",13);gsub("IBS",14);gsub("ITU",15);gsub("JPT",16);gsub("KHV",17);gsub("LWK",18);gsub("MSL",19);gsub("MXL",20);gsub("PEL",21);gsub("PJL",22);gsub("PUR",23);gsub("STU",24);gsub("TSI",25);gsub("YRI",26);print}' file.txt

而且效果很好。我做错了什么?

@ChrisLear 给了我一个可行的解决方案,但我仍然不太明白命令解决方案在做什么。这是工作代码:

$(printf "awk {%sprint}" $(tail -n +2 file.txt | cut -f2 | sort | uniq | awk 'BEGIN{a=1}{printf "gsub(\"%s\",%i);", $1,a++}')) file.txt

{%sprint} 周围的单引号被删除。为什么那些单引号会破坏命令替换?

编辑:将反引号更改为 $(...) 表示法。还添加了我不明白的解决方案。

【问题讨论】:

  • 正确的做法是awk '{gsub("ACB",1);gsub("ASW",2)}' btw 是awk 'BEGIN{split("ACB ASW",m)} {for (i in m) gsub(m[i],i)}' 或类似的(取决于您的要求),但这似乎与您的问题无关。
  • @EdMorton 命令是printf "awk '{%sprint}'" $(...) %s 指的是$(...)
  • 啊,我明白了。我尝试正确格式化您的问题,但您在 printf 行的开头有 3 个刻度,所以我猜您想留下一个,但写下来没有意义 - 请 edit 您的问题显示实际命令行。另外 - 添加简洁、可测试的示例输入和预期输出,因为您所做的事情不太可能是正确的方法(无论“它”是什么),我们可以帮助您走上正确的道路。
  • @EdMorton 我使用额外的反引号来包装长命令,但我想这不是首选格式。
  • stackoverflow.com/questions/18567685/… 可能是一个有用的参考

标签: bash awk command-substitution


【解决方案1】:

尝试从正在生成的命令中删除引号。

`printf "awk {%sprint}" $(tail -n +2 file.txt | cut -f2 | sort | uniq | awk 'BEGIN{a=1}{printf "gsub(\"%s\",%i);", $1,a++}')` file.txt

有关解释,请参阅Why does command substitution change how quoted arguments work? 接受的答案

【讨论】:

  • 这行得通,但我不太明白原因。我查看了链接的答案,并不太明白发生了什么。
  • 您的命令不起作用的原因是,在命令替换(最初是反引号)之后,生成的命令对其应用了分词,但被替换命令中的引号都是按字面处理的。我在网上找到了各种不太好的解释,我链接到的解释是我认为在澄清问题方面做得最好的解释。不幸的是,我怀疑我能否以更清晰的方式重新陈述它。
【解决方案2】:

看起来您正试图从文件的第 2 行开始获取一堆唯一的第二个字段,并根据它们的字母顺序将它们映射到数字,然后将更改应用到同一个文件。如果是这样,那么使用 GNU awk 进行 sorted_in 和就地编辑将是:

awk -i inplace '
NR==FNR {
    if (NR>1) {
        map[$2]
    }
    next
}
FNR==1 {
    PROCINFO["sorted_in"] = "@ind_str_asc"
    for (str in map) {
        map[str] = ++i
    }
}
{
    $2 = map[$2]
    print
}
' file.txt

如果这不是您需要的,请编辑您的问题以显示简洁、可测试的示例输入和预期输出。

【讨论】:

  • 我要做的是将文本文件列中的所有字符串替换为按字母顺序排序时与每个唯一字符串相对应的数字。但我的问题是关于为什么命令替换不起作用的更普遍的问题。
  • 您问题中发布的命令行没有意义,因此我们无法帮助您调试它,由于虚假滴答声,这显然是现在编写的无效语法,可能是由于我们俩试图为这个论坛格式化它,这就是为什么我要求你编辑它,所以它实际上是你试图执行的命令。
  • 抽动不是假的。我正在尝试进行命令替换。我已经确认在 tic 中运行代码,然后将输出复制到下一行并附加文件名正是我想要做的。所以问题是为什么命令替换会中断。我尝试了这个解决方案,它只是删除了第二列
  • 但是您已经知道 $(...) 那么为什么要使用它们在外部替换的旧式反引号,即为什么要使用 `cmd1 $(cmd2)` 而不是 $(cmd1 $(cmd2))?你试过在你的代码上运行 shellcheck 吗?
  • 那是我的马虎,但修复它只会产生不同的错误。 @ChrisLear 的解决方案有效,但我仍然不太了解机制,我也不明白为什么这个解决方案不起作用。看起来应该。 gawk 无法识别 -i inplace
猜你喜欢
  • 2014-08-06
  • 1970-01-01
  • 2023-03-16
  • 2019-07-06
  • 2021-05-10
  • 2012-04-02
  • 2014-02-06
  • 2016-03-19
  • 1970-01-01
相关资源
最近更新 更多