【问题标题】:AWK: append text to specific line with 'system(external programm)' substitutionAWK:使用“系统(外部程序)”替换将文本附加到特定行
【发布时间】:2021-09-06 12:21:09
【问题描述】:

我有一个名为 data 的文件,如下所示:

orange
apple
pair
mango
grape

通过使用 awk -i inplace '{if (NR==4) $0=$0" is sweet"}{print}' data,我明白了:

orange
apple
pair
mango is sweet
grape

我正在尝试通过system() 获得相同的结果,但我不知道如何。

echo is sweet | xclip

xclip -o 输出is sweet。我在努力

awk -i inplace '{if (NR==4) $0=$0(system("xclip -o"))}{print}' data

cat -n data 给了我

     1  orange
     2  apple
     3  pair
     4  is sweet
     5  mango0
     6  grape

芒果和葡萄被推下一行,is sweet 独立在第 4 行,mango 最后有一个0

如何更改命令,并且仍然使用system("xclip -o"),以便第 4 行显示mango is sweet,在任何地方都没有附加0,也没有额外的行,即与第一个示例一样?

我对 awk 非常陌生,如果能提供任何帮助,我们将不胜感激。

【问题讨论】:

    标签: awk command-substitution


    【解决方案1】:

    system("foo") 只是调用程序foo 并返回foos 退出状态(即,0 表示成功,非零表示失败)。您想要捕获foo输出(即foo 写入标准输出的文本),而不是退出状态,因此调用system() 是错误的方法。您在问题中看到的是 xclip -o 的输出与您的 awk 脚本的输出混合在一起。

    这就是你想做的事情(使用date 而不是xclip,因为这是每个人都可以使用的命令):

    $ awk '
        NR==4 {
            cmd = "date +%F"
            $0 = $0 " " ( (cmd | getline line) > 0 ? line : "N/A" )
            close(cmd)
        }
        { print }
     ' file
    orange
    apple
    pair
    mango 2021-09-06
    grape
    

    请参阅https://www.gnu.org/software/gawk/manual/gawk.html#Getline_002fVariable_002fPipe 了解有关上述内容的更多信息,并确保阅读http://awk.freeshell.org/AllAboutGetline 以了解我为什么在使用getline 的输出之前测试它的退出状态,以及为什么它在许多情况下都不能使用(但这个是合适的)。

    作为“单行”,上述内容将是:

    awk 'NR==4 { cmd = "date +%F"; $0 = $0 " " ( (cmd | getline line) > 0 ? line : "N/A" ); close(cmd) } { print }' file
    

    如果它有用,这里有一个函数,它可以与 awk 等效,作为 shell 的命令替换:

    $ cat cmdsub.awk
    function cmdsub(cmd,    line, n, out, cmd_stat, gl_stat) {
        ERRNO = ""
        while ( ( gl_stat=(cmd | getline line) ) > 0 ) {
            out = (n++ ? out ORS : "") line
        }
        cmd_stat = close(cmd)
    
        # If the above pipeline loop succeeded then all 3 error/status
        # variables will be 0 but if the above pipeline loop failed then
        #
        #    a) if cmd failed then
        #           i) ERRNO will be null
        #          ii) gl_stat will be 0 if 1st iteration, 1 otherwise.
        #         iii) cmd_stat will be non-zero if GNU awk,
        #                   poorly defined for POSIX awk so YMMV.
        #
        #    b) if cmd succeeded and getline failed then
        #           i) ERRNO will be non-null if GNU awk, null otherwise.
        #          ii) gl_stat will be less than zero
        #         iii) cmd_stat will be 0
    
        if ( (ERRNO == "") && ( (gl_stat != 0) || (cmd_stat != 0) ) ) {
            ERRNO = sprintf("CMD_STAT: %d, GL_STAT: %d", cmd_stat, gl_stat)
        }
    
        return out
    }
    BEGIN {
        print "foo", cmdsub("date +%F"), "bar"
        print (ERRNO ? "Failure: " ERRNO : "Success")
        exit (ERRNO ? 1 : 0)
    }
    

    $ awk -f cmdsub.awk
    foo 2021-09-06 bar
    Success
    
    $ echo $?
    0
    

    它使用一个名为 ERRNO 的全局变量,与 gawk 用于 getline 失败的相同(注意:尽管它的名字,ERRNO 是一个字符串,而不是一个数字),并依赖于 close(cmd) 返回一个失败cmd 失败时的退出状态,这在 gawk 中发生,但在其他 awks YMMV 中发生,因为 POSIX 标准在这一点上含糊不清。

    有关ERRNOclose() 的更多信息,请参阅:

    【讨论】:

    • 我正在我的 Ubuntu 最新 lts Ed 上尝试您建议的命令,并引发错误:awk: cmd. line:1: NR==4 {cmd="date +%F" $0=$0 " " ((cmd | getline line) > 0 ? line : "N/A") close(cmd)}{print} awk: cmd. line:1: ^ syntax error
    • 我发布的脚本中没有任何内容会导致任何 awk 中的语法错误,因此要么复制/粘贴错误,要么从更大的 shell 脚本中调用它,这有问题。如果是后者,请尝试将其复制/粘贴到shellcheck.net 以查看是否有帮助。否则,将您正在执行的命令准确复制/粘贴到您的问题中(不是无法正确格式化的注释),以便我们可以看到该命令是什么。
    • 你是对的 Ed,我没有复制/粘贴,而是将命令写在一行中,可能有一些空格错误,就像我经常做的那样!非常感谢您的解决方案。它工作得很好!
    • 实际上我无法理解 Ed,试图在一行中编写您的命令,如果在 "date +%F"$0 = $0 之间没有换行,则会引发错误。
    • 非常感谢您花时间澄清每一个小细节。我真的很感激!
    猜你喜欢
    • 2018-06-30
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-27
    • 1970-01-01
    相关资源
    最近更新 更多