【问题标题】:Difference in newlines in output between awk's printf and sprintfawk\'s printf 和 sprintf 之间输出换行符的差异
【发布时间】:2022-08-06 08:49:29
【问题描述】:

Gawk 手册says about sprintf: \"返回(不打印)printf 将打印出的字符串...\"

这是 printf 输出:

awk \'{ printf \"%s\", $0 }\' <<< \'line1
line2\'
line1line2%

但是, sprintf 似乎保留了换行符:

awk \'{ my_var=sprintf(\"%s\", $0); print my_var }\' <<< \'line1
line2\'
line1
line2

(与 BSD 和 GNU awk 相同。)

为什么会这样?

如何在不使用 RS/ORS/sub 的情况下以这种方式将换行符内容放入变量中?

  • print 打印换行符。你在做my_var=soemthing; printHow do I put in a variable the newline-stripped content this way它在$0,如果你不想打印换行符,用printf打印。 printf \"%s\", my_var
  • @KamilCuk,如果变量是单行的,我想下面的命令应该将两行打印为一行。请注意,没有print。但事实并非如此。 awk \'/line1/,/line2/ { out=sprintf(\"%s\", $0); match(out, /line1.*/); print out }\' &lt;&lt;&lt; \'line1 \\ line2\'
  • print out打印换行符. print 打印参数加上换行符. awk \'/line1/,/line2/ { out=sprintf(\"%s\", $0); match(out, /line1.*/); printf out }\' &lt;&lt;&lt;$\'line1 \\\\\\nline2\'

标签: awk


【解决方案1】:

如果你想删除'\n'

如果你想去掉换行符,那么sed 让这很容易:

$ sed '/[\]/{N;s/\n//}' <<< 'line1 \
line2'
line1 \line2

或者您可以使用awk 作为:

$ awk '/\\$/ {line = line $0; next} { print line $0; line = ""}' <<< 'line1 \
line2'
line1 \line2

您只需连接以\ 结尾的行,然后输出所有连接的行以及不以'\' 结尾的第一行的当前行,并重置您正在累积行的变量(上面的line)。

您可以通过将/\\[[:blank:]]*$/ 添加到您的正则表达式来处理'\' 和行尾之间的尾随空格。

如果我错过了您的意图,请告诉我,我很乐意为您提供进一步的帮助。

【讨论】:

  • David C. Rankin,谢谢,但我需要将它放在一个变量中以传递给 match(),否则我会很容易地使用 print(正如您所建议的那样)或 printf。行尾的实际内容中也可能没有反斜杠。不幸的是,Sed 是没有选择的。
  • 好的,我明白你在说什么。如果行尾没有'\' - 你怎么知道你想加入哪些行以及哪些行作为单独的行离开?对于变量,您可以使用awk -v var="$shellvar" '{...}' 从shell 传递到awk,这将使awk 变量var 保存shell 中"$shellvar" 的内容。让我知道如何确定要加入的行。如果您只想在 awk 中的变量中包含整行,myvar = $0 可以正常工作(就像我在示例中使用的 line 一样)
  • 另外,当您说“我需要它在变量中”时,您要捕获的“它”是什么?整个记录还是记录中的最后一个字段?如果是最后一个字段(如'\'),您可以使用myvar = $NF 来捕获最后一个字段。如果这将使字段数在数字上比您不加入的行数多一,那么您将NF 作为用于做出该决定的关键。
  • 这是(有点简化的)真实代码,它应该返回line(反斜杠作为有换行符的视觉线索):awk '/line1/,/line2/ { out=sprintf("%s", $0); match(out, /line1.*line2/); out=substr($0, RSTART+6, RLENGTH-12); print out }' &lt;&lt;&lt; 'line1 \ line \ line2' 我也无法更改 RS/ORS。
  • 使用"'line1\nline\nline2" 作为您的输入,您想要的输出是什么。这就是我对我们要去的地方仍然有点模糊的地方。起初我只是想你想在每行延续'\' 之后删除\n',但现在我怀疑你在追求别的东西。所以如果我的输入行正确——你希望你的输出是什么样的?
【解决方案2】:

关于sprintf seems to preserve newlines - 不,awk 在读取记录时会使用换行符。在:

awk '{ my_var=sprintf("%s", $0); print my_var }' <<< 'line1
line2'

$0 从不包含换行符,因此 sprintf 的输出不包含换行符。 print 命令添加输出my_var 时换行。如果你这样做了:

print "<" my_var ">"

那么你会看到my_var 不包含换行符,换行符出现在&gt; 之后,而不是之前。

我在上面说的是newline,但实际上RS 在输入上的值和ORS 在输出上的值都是一样的,默认情况下它们都是换行符。

关于How do I put in a variable the newline-stripped content this way - 这已经是它包含的内容了。如果您希望 my_var 然后在不附加换行符的情况下输出,请执行以下操作:

printf "%s", my_var

或这个:

ORS=""; ...; print my_var

【讨论】:

    【解决方案3】:

    如果您在中间使用换行符提供 awk(2 条记录)数据,即:

    <<<'line1
    line2'
    

    awk 将逐条处理输入记录(注意代码中的NR,不要介意printf 后面的()

    $ awk '{ printf("%s %s", NR, $0) }' <<< 'line1
    line2'
    1 line12 line2$
    

    或者

    $ awk '{ print sprintf("%s %s", NR, $0) }' <<< 'line1
    line2'
    1 line1
    2 line2
    $
    

    前者printf 没有在任何一条记录之后产生换行符,后者print 有。

    如果您想保留换行符(在记录之间),请立即读取整个数据而不处理换行符(嗯,这确实涉及使用RS):

    $ awk -v RS="^$" '{ printf("%s %s", NR, $0) }' <<< 'line1
    line2'
    1 line1
    line2
    $
    

    如果您无法使用RS,则需要自己解析输入。样本数据,cat file

    line1
    line2 \\
    line3 \
    line4
    line5
    

    \ 标记附加 2 条记录,\\ 是反斜杠:

    $ awk '{
        if(/[^\\]\\$/) {                      # if ends in one \
           b=b substr($0,1,length($0)-1) ORS  # append to buffer b
           next                               # on to next record
        }
        $0=b $0                               # prepend buffer to record
        gsub(/\\\\/,"\\")                     # \\s to \s
        print sprintf("%s %s", ++c, $0)       # output, NR replace with c 
        b=""                                  # empty the buffer
    }' file
    

    输出:

    1 line1
    2 line2 \
    3 line3 
    line4
    4 line5
    

    【讨论】:

      【解决方案4】:

      如何以这种方式将换行符剥离的内容放入变量中, 不使用 RS/ORS/sub?

      使用sprintf 返回值作为printf 的参数,考虑以下示例,让file.txt 内容为

      12.12 14.14 16.16
      

      然后

      awk '{x=sprintf("%d",$1);y=sprintf("%d",$2);z=sprintf("%d",$3)}END{printf "%s%s%s",x,y,z}' file.txt
      

      给出输出

      121416
      

      (没有尾随换行符)

      (在 GNU Awk 5.0.1 中测试)

      【讨论】:

        【解决方案5】:

        如果你只是想在没有\n 的情况下连接它:

        % jot 30 | mawk _^_ ORS=
        
        123456789101112131415161718192021222324252627282930%  # "...%" = no trailing \n
        

        要添加 1 个尾随换行符,通过管道更容易:

        jot 30 | gawk // ORS= | nawk $$
        
        123456789101112131415161718192021222324252627282930
        

        在剥离所有输入换行符的同时添加尾随新行的另一种方法是:

        mawk2 ++NF OFS= RS= FS='\412'  
        
        123456789101112131415161718192021222324252627282930
        

        如果您想将垂直输入转换为水平输入:

        nawk NF=NF FS='\n' RS= 
        
        1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
        

        水平的没有尾随换行符:

        gawk 8 ORS=' ' 
        
        1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30%
        

        【讨论】:

          猜你喜欢
          • 2018-08-12
          • 1970-01-01
          • 1970-01-01
          • 2017-01-17
          • 2020-11-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多