在Unix命令行上简洁便携的“加入”

时间:2011-12-15 15:54:51

标签: shell unix

如何将多行连接到一行,使用分隔符表示换行符,并避免使用尾随分隔符,并可选择忽略空行?

实施例。考虑一个文本文件foo.txt,有三行:

foo
bar
baz

所需的输出是:

foo,bar,baz

我现在使用的命令:

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

理想情况下会是这样的:

cat foo.txt |join ,

什么是:

  1. 最便携,简洁,易读的方式。
  2. 使用非标准unix工具的最简洁方法。
  3. 当然我可以写一些东西,或者只是使用别名。但我很想知道这些选择。

9 个答案:

答案 0 :(得分:115)

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

paste -s -d","

这不会处理你提到的空行。为此,首先通过grep管道您的文字:

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

答案 1 :(得分:12)

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'

答案 2 :(得分:8)

如何使用xargs?

适合您的情况

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

注意xargs命令的输入限制长度。 (这意味着无法处理很长的输入文件。)

答案 3 :(得分:6)

的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'

答案 4 :(得分:4)

只是为了好玩,这是一个全能的解决方案

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

如果尾随换行有问题,您可以使用printf代替echo

这可以通过将IFSread将拆分的分隔符)设置为新行而不是其他空格,然后告诉read不会停止阅读直到达到{{{} 1}},而不是它通常使用的换行符,并将读取的每个项目添加到数组(nul)数据中。然后,在子shell中,以便不破坏交互式shell的-a,我们将IFS设置为IFS并使用,展开数组,该数组分隔每个项目*

中第一个字符的数组

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

使用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)不是标准扩展和实用程序it-self更加面向流,因此它不那么便携。

答案 7 :(得分:0)

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

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 :(得分:-1)

我的回答是:

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

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