【问题标题】:Error calling system() within awk在 awk 中调用 system() 时出错
【发布时间】:2014-09-06 16:37:17
【问题描述】:

我正在尝试执行一个系统命令来找出一个 csv 文件在其前七个字符中有多少个唯一引用,作为处理相同 csv 文件的更大 awk 脚本的一部分。有重复的条目,我不想让 awk 解析整个文件两次,所以我避免使用 NR。这部分脚本的要点是:

#!/bin/bash
awk '
{
  #do some stuff, then when finished, count the number of unique references
  productFile="BusinessObjects.csv";
  systemCall = sprintf( "cat %s | cut -c 1-7 | sort | uniq | wc -l", $productFile );
  productCount=`system( systemCall )`-1; #subtract 1 to remove column label row
}' < BusinessObjects.csv

而且解释器不喜欢它:

awk: cmd. line:19: ^ syntax error ./awkscript.sh: line 38: syntax error near unexpected token '(' ./awkscript.sh: line 38: systemCall = sprintf( "cat %s | cut -c 1-7 | sort | uniq | wc -l", $productFile );

如果我硬编码系统命令

productCount=`system( "cat BusinessObjects.csv | cut -c 1-7 | sort | uniq | wc -l" )`-1;

我明白了:

./awkscript.sh: command substitution: line 39: syntax error near unexpected token '"cat BusinessObjects.csv | cut -c 1-7 | sort | uniq | wc -l"' ./awkscript.sh: command substitution: line 39: 'system( "cat BusinessObjects.csv | cut -c 1-7 | sort | uniq | wc -l" )'

从技术上讲,我可以在 shell 脚本开始时在 awk 之外执行此操作,将结果存储在系统变量中,然后使用 -v 将其传递给 awk,但这不利于 awk 脚本的可读性(它有几百行长)。我在错误的地方有空格或引号吗?我试过摆弄,但我似乎无法以解释器接受的方式呈现对 system() 的调用。最后,有没有更明智的方法来做到这一点?


编辑: csv 文件确实是用分号分隔的,因此最好使用分隔符而不是字符数进行剪切(谢谢!)。

ProductRef;Data1;Data2;等

1234567;等;等;等


编辑 2: 我正在尝试解析一个 csv 文件,该文件的第一列充满了 N 个唯一的产品引用,并创建了一系列关联的 HTML 页面,其中包括“N 页 n”信息字段。这是(显然很痛苦)我第一次使用 awk,但它似乎是解析 csv 文件的合适工具。因此,我试图计算并返回唯一引用的数量。在外壳上

剪切-d\; -f1 业务对象.csv |排序 |独特 | wc -l

工作正常,但我无法通过这样做在 awk 中工作

#!/bin/bash
if [ -n "$1" ]
then
        productFile=$1
else
        echo "Missing product file argument."
        exit
fi

awk -v productFile=$productFile '
BEGIN {
        FS=";";
        productCount = 0;
        ("cut -d\"\;\" -f1 " productFile " | sort | uniq | wc -l") | getline productCount;
        productCount -=1; #remove the column label row
}

{
print productCount;
}'

如果我不将分号包含在 \"\;\" 中,我会在剪切代码上收到语法错误,并且脚本会挂起,而不会在我这样做时打印任何内容。

【问题讨论】:

  • 为什么它在反引号中?还有为什么 sprintf 没有被引用?还有为什么$productFile。这个脚本一团糟
  • 您能添加 BusinessObjects.csv 的 sn-p 吗?如果有列分隔符,你也可以使用 cut –d';' -f1 yourFile
  • @Jidder,我原来有 productCount=system(sprintf("cat %s | cut -d';' | sort | uniq | wc -l", productFile))-1;然后开始摆弄试图找到语法错​​误,当我对 bash 和 awk 感到困惑时,它变成了 frankencode。
  • 这一切都可以在 awk 中完成,虽然我不知道你为什么使用系统调用。你到底想做什么。你能发布预期的输出吗?
  • 你是什么意思你避免 NR 因为你不希望它解析文件两次?

标签: bash shell awk syntax-error


【解决方案1】:

我不记得你可以在 awk 中使用反引号。

  productCount=`system( systemCall )`-1; #subtract 1 to remove column label row

您可以不使用 system 直接运行命令,而是使用 getline 来读取输出:

  systemCall | getline productCount
  productCount -= 1

或者更完整

  productFile = "BusinessObjects.csv"
  systemCall = "cut -c 1-7 " productFile " | sort | uniq | wc -l"
  systemCall | getline productCount
  productCount -= 1
  • 无需使用sprintf 并包含cat
  • 将字符串分配给变量也是可选的。你可以只用"xyz" | getline ...
  • 如果支持,sort | uniq 可以只是 sort -u
  • 如果文件名包含可能会混淆命令的空格或字符,则可能需要引用。
  • getline 可能会以不同于预期的方式更改全局变量。见https://www.gnu.org/software/gawk/manual/html_node/Getline.html

【讨论】:

  • 谢谢,我添加了一个编辑,使您的方法适应我想要实现的目标。不幸的是,我仍然无法通过 getline 执行 bash 代码并且不明白为什么。
  • @user48493 你不应该在()周围加上字符串。
  • 另外,{ print productCount; } 永远不会在没有文件的情况下运行。
  • 我还建议您应用打印语句,以便您可以跟踪 awk 代码的运行时间。
  • 另外,我意识到我的原始代码在前面有一个注释行,单词中有一个撇号,这使 awk 解释器失活并使我感到困惑(getline 代码在整个过程中返回了一个语法错误两个不同的行,而实际上语法名义上是可以的)。经验教训:#不要这样做!
【解决方案2】:

这样的选择可以吗?

$ cat productCount.sh
#!/bin/bash
if [ -n "$1" ]
then
        productCount=`cat $1 | cut -c 1-7 | sort | uniq | wc -l`
        echo $productCount
else
        echo "please supply a filename as parameter"
fi

$ ./productCount.sh BusinessObjects.csv
9

【讨论】:

  • 谢谢,但我真的很想知道是否可以在 awk 中使用 system() 执行此操作,而不是在脚本开头调用 bash 代码,然后使用 -v 将 productCount 传递给 awk .或者,如果这是不好的做法,请解释原因。
  • 也许这回答了你的问题:stackoverflow.com/questions/10008407/…
猜你喜欢
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-21
  • 2010-10-15
相关资源
最近更新 更多