【问题标题】:Concise and portable "join" on the Unix command-lineUnix 命令行上的简洁和可移植的“join”
【发布时间】:2011-12-15 15:54:50
【问题描述】:

如何将多行合并为一行,在换行符所在的位置使用分隔符,并避免尾随分隔符,并且可以选择忽略空行?

示例。考虑一个包含三行的文本文件foo.txt

foo
bar
baz

想要的输出是:

foo,bar,baz

我现在使用的命令:

tr '\n' ',' <foo.txt |sed 's/,$//g'

理想情况下是这样的:

cat foo.txt |join ,

是什么:

  1. 最便携、简洁、易读的方式。
  2. 使用非标准 unix 工具的最简洁方式。

当然我可以写一些东西,或者只是使用别名。但我很想知道这些选项。

【问题讨论】:

标签: shell unix


【解决方案1】:

也许有点令人惊讶,paste 是一个很好的方法:

paste -s -d","

这不会处理您提到的空行。为此,首先通过grep 传送您的文本:

grep -v '^$' | paste -s -d"," -

【讨论】:

  • @codaddict 我也不是,但我必须承认我觉得它一点也不直观——我总是需要查看手册页。我很想看看其他人的建议。
  • 还有其他方法,但没有更好的方法(而且有趣的方法有点害羞)。
  • 它似乎并没有忽略空行,但这仍然非常好,适用于我的用例。谢谢!
  • 为了增强可移植性,当预期从stdin 读取时,请考虑在paste 命令的末尾添加-。 (paste 的某些版本,例如 BSD,不会从 stdin 读取,除非 - 明确传递给它。)
  • 感谢paste 的提示!我注意到它只允许单字符分隔符,默认为\t。完成更长的分隔符(例如, ):cat foo.txt | paste -s | sed 's/\t/, /g'
【解决方案2】:

这个sed 一行应该可以工作-

sed -e :a -e 'N;s/\n/,/;ba' file

测试:

[jaypal:~/Temp] cat file
foo
bar
baz

[jaypal:~/Temp] sed -e :a -e 'N;s/\n/,/;ba' file
foo,bar,baz

要处理空行,您可以删除空行并将其通过管道传输到上述单行。

sed -e '/^$/d' file | sed -e :a -e 'N;s/\n/,/;ba'

【讨论】:

  • 解释一下就好了!
  • 将两个-e表达式合二为一更清晰,sed -e ':a; N; s/\n/,/; ba'。但这仍然是一个 O(n²) 方法,因为每次添加新行时 sed 都会进行一些替换。 sed -e ':a; N; $!ba; s/\n/,/g' 是线性的,在所有行都附加到 sed 的模式空间后只替换一次。 $!ba 表示“如果是最后一行 ($) 不要 (!) 跳转到 (b) 标签 :a (a),请打破循环”
【解决方案3】:

如何使用 xargs?

适合你的情况

$ cat foo.txt | sed 's/$/, /' | xargs

注意 xargs 命令的输入长度限制。 (这意味着很长的输入文件不能被它处理。)

【讨论】:

  • 我发现 xargs 上的 -L 标志很有帮助 -L 50 将每行 50 个项目。
【解决方案4】:

Perl:

cat data.txt | perl -pe 'if(!eof){chomp;$_.=","}'

或者更短更快,令人惊讶的是:

cat data.txt | perl -pe 'if(!eof){s/\n/,/}'

或者,如果你愿意:

cat data.txt | perl -pe 's/\n/,/ unless eof'

【讨论】:

  • 这样做的好处是您可以使用任何字符串而不是简单的逗号。公认的答案不太通用。我特别喜欢最后的迭代,虽然我会这样写:perl -pe 's/\n/,/ unless eof' data.txt(不需要假猫)。
【解决方案5】:

只是为了好玩,这是一个全内置解决方案

IFS=$'\n' read -r -d '' -a data < foo.txt ; ( IFS=, ; echo "${data[*]}" ; )

如果尾随换行符有问题,您可以使用printf 而不是echo

这可以通过将IFSread 将拆分的分隔符)设置为仅换行符而不是其他空白符来实现,然后告诉read 在到达nul 之前不要停止阅读,而不是换行符它通常使用,并将读取的每个项目添加到数组(-a)数据中。然后,在一个子shell中,为了不破坏交互式shell的IFS,我们将IFS设置为,并用*扩展数组,它用@中的第一个字符分隔数组中的每个项目987654333@

【讨论】:

  • 有趣,但是可移植性不是很好,因为在纯sh shell read 命令中没有-d 选项。
  • @mykhal:是的。但是,bash 可以在许多系统上找到,因此它具有一些实用性。如果您希望可移植性数组也可能已淘汰,否则您可以简单地使用while 循环来解决缺少-d 的问题。对于一个合适的、可移植的全内置版本,您需要类似c= ; while IFS= read -r d ; do if ! [ -z "$d" ] ; then printf "$c$d" ; fi c=, ; done &lt; foo.txt 的东西,但对于知道-rread 仍然失败,但这可以省略,并假定内置printf,所以echo如果效率很重要,那里可能会更好。不过,公认的答案要好得多!
【解决方案6】:

我需要完成类似的事情,从文件中打印以逗号分隔的字段列表,并且很高兴将 STDOUT 传送到 xargsruby,如下所示:

cat data.txt | cut -f 16 -d ' ' | grep -o "\d\+" | xargs ruby -e "puts ARGV.join(', ')"

【讨论】:

    【解决方案7】:

    我有一个日志文件,其中一些数据被分成多行。发生这种情况时,第一行的最后一个字符是分号 (;)。我使用以下命令加入了这些行:

    for LINE in 'cat $FILE | tr -s " " "|"'
    do
        if [ $(echo $LINE | egrep ";$") ]
        then
            echo "$LINE\c" | tr -s "|" " " >> $MYFILE
        else
            echo "$LINE" | tr -s "|" " " >> $MYFILE
        fi
    done
    

    结果是一个文件,其中在日志文件中拆分的行是我的新文件中的一行。

    【讨论】:

      【解决方案8】:

      使用ex(也忽略空白行)就地加入空格的简单方法,使用:

      ex +%j -cwq foo.txt
      

      如果要将结果打印到标准输出,请尝试:

      ex +%j +%p -scq! foo.txt
      

      要连接不带空格的行,请使用+%j! 而不是+%j

      要使用不同的分隔符,这有点棘手:

      ex +"g/^$/d" +"%s/\n/_/e" +%p -scq! foo.txt
      

      其中g/^$/d(或v/\S/d)删除空行,s/\n/_/ 是替换,基本上与使用sed 相同,但适用于所有行(%)。解析完成后,打印缓冲区 (%p)。最后-cq!执行vi q!命令,基本不保存就退出(-s是静音输出)。

      请注意ex 等同于vi -e

      这种方法非常可移植,因为大多数 Linux/Unix 默认都带有ex/vi。而且它比使用 sed 更兼容,其中就地参数 (-i) 不是标准扩展,并且实用程序本身更面向流,因此它不是那么便携。

      【讨论】:

        【解决方案9】:

        POSIX 外壳:

        ( set -- $(cat foo.txt) ; IFS=+ ; printf '%s\n' "$*" )
        

        【讨论】:

          【解决方案10】:

          我的答案是:

          awk '{printf "%s", ","$0}' foo.txt
          

          printf 就够了。我们不需要-F"\n" 来更改字段分隔符。

          【讨论】:

          • 这会在输出的开头添加一个伪逗号。 -1 表示未测试。
          猜你喜欢
          • 2019-02-03
          • 2010-11-17
          • 1970-01-01
          • 2014-08-06
          • 2010-11-10
          • 1970-01-01
          • 2010-11-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多