awk shell参数FILENAME vs ARGV

时间:2017-01-25 13:53:46

标签: shell awk

试图解决这个问题append wc...我无法理解如何捕获作为awk命令参数传递的文件名。

awk 'BEGIN {for ( i=1;i<ARGC;i++ )print "ARGV " i ": [" ARGV[i] "]" }
     FNR==1 {print "FILENAME " ++a ": [" FILENAME "]" }
    ' $( ls )

适用于标准文件名,例如file1.txt,但是间隔文件名lile file with space会出现问题(实际上当文件名包含$ IFS字符且IFS不是要触摸)。 FILENAME没问题,ARGV在空格上是分开的(引用或不引用),就好像在shell传递后将所有参数解析为一个字符串一样。

我使用它来计算文件行,即使文件是空的(因此永远不会达到FNR == 1),但这不是问题。

所以

  1. 我应该如何格式化间隔字符(我尝试使用引用来覆盖像$( ls | sed "s/'/'\"'\"'/g;s/.*/'&'/")这样的引用,但没有帮助)
  2. 如何通过ARGV捕获间隔值
  3. 我在linux和AIX上使用awk(在这种情况下不是gawk :-()

    一些样本

    #ls -1 file*
    file
    file and space
    file'qu .txt
    file"qu .txt
    
    # awk '...' "file and space"
    ARGV 1: [file and space]
    FILENAME 1: [file and space]
    
    # awk '...' $( ls file* | sed -e 's/ /?/g' )
    ARGV 1: [file]
    ARGV 2: [file and space]
    ARGV 3: [file'qu .txt]
    ARGV 4: [file"qu .txt]
    FILENAME 1: [file]
    FILENAME 2: [file and space]
    FILENAME 3: [file'qu .txt]
    

    最后ls显示awk可能有所不同(文件“qu .txt 是一个空文件,因此FNR == 1永远不会到达)。

    我现在看到这是在shell传递信息级别,而不是awk。

2 个答案:

答案 0 :(得分:4)

问题与awk无关,而与 shell (如何传递文件名)无关:

不带引号的命令替换$( ls )将扩展为文件名列表,但文件名受字拆分,因此带有嵌入空格的文件名每个都被分成多个传递给awk的参数。

这会导致awk看到不存在的文件名(此时发生致命错误)或意外处理不同的文件(多次);例如,如果文件file onefileone都存在于当前目录中,则awk处理file one,并且而是两次处理fileone

在这种情况下,一个简单的glob(*)将,其扩展结果受制于工作分割,并且通常优于解析ls输出:

awk 'BEGIN {for ( i=1;i<ARGC;i++ )print "ARGV " i ": [" ARGV[i] "]" }
     FNR==1 {print "FILENAME " ++a ": [" FILENAME "]" }
    ' *

使用不带引号的命令替换扩展为传递给命令的多个参数(command $(...))通常是一种反模式,因为结果输出不仅受到 - 分裂,但也是 globbing (文件名扩展),作为所谓的shell expansions的一部分。

诊断问题:

$ touch file 'file 1'
$ bash -s - $(ls file 'file 1') <<<'echo "$# args passed: [$1] [$2] [$3]"'
3 args passed: [file] [file] [1]

请注意,即使file 1与引号一起传递,目标命令(ad-hoc bash脚本)也会看到 3 参数,因为shell已损坏{{ 1}}由于不加引号使用file 1(命令替换)而成为单独的参数file1(分词)。
(注意$(...)没有帮助,因为命令输出总是作为单个参数传递。)

以下简化命令会导致"$(...)" 从根本上失败,因为它不会看到单个文件名awk,而是会看到文件名File OneFile ,两者都不存在:

One

以上是 GNU $ rm -f File One; echo 'hi from File One' > 'File One' $ awk '{ print FILENAME }' $(ls 'File One') awk: fatal: cannot open file `File' for reading (No such file or directory) 的错误消息; BSD Awk和Mawk基本上表现相同,除了错误消息的措辞的变化。在这种情况下,所有这些实现都将退出代码设置为awk

答案 1 :(得分:1)

这会在你的特定shell中起作用吗?

declare -a files=(*)
awk 'BEGIN {for ( i=1;i<ARGC;i++ )print "ARGV " i ": [" ARGV[i] "]" }
     FNR==1 {print "FILENAME " ++a ": [" FILENAME "]" }
    ' "${files[@]}"

阵列扩展也应该回避你的问题,希望如此。