在Unix命令行上简洁和可移植的“连接”

我怎样才能将多行代码连接成一行,分隔符是换行符,避免尾随分隔符,还可以忽略空行?

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

 foo bar baz 

期望的输出是:

 foo,bar,baz 

我现在使用的命令是:

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

理想情况下,这将是这样的:

 cat foo.txt |join , 

什么是:

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

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

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

 paste -s -d"," 

这不会处理你提到的空行。 为此,首先通过greppipe道input文本:

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

这个sed单行应该工作 –

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

testing:

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

如何使用xargs?

为你的情况

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

注意xargs命令的input限制长度。 (这意味着很长的input文件不能由此处理。)

只是为了好玩,这里是一个完整的解决scheme

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

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

这可以通过设置IFS ,将read的分隔符分割为新行,而不是其他空格,然后告诉read不停止读取直到达到nul ,而不是通常使用的换行符,并将读取的每个项数组( -a )数据。 然后,在一个子shell中,为了不打断交互式shell的IFS ,我们将IFS设置为,然后用*扩展数组,它用IFS的第一个字符来IFS数组中的每个项

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' 

我需要做一些类似的事情,从文件中打印一个以逗号分隔的字段列表,并很高兴将pipe道输出转换为xargsruby ,如下所示:

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

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

 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 

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

简单的方法来使用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相同,但是对于所有行( % )。 parsing完成后,打印缓冲区( %p )。 最后-cq! 执行vi q! 命令,基本退出而不保存( -s是使输出静音)。

请注意ex相当于vi -e

这个方法非常便于使用,因为大部分的Linux / Unix都默认使用ex / vi 。 而且它比使用sed更加兼容,其中in-place参数( -i )不是标准扩展,它的实用性更多地面向stream,因此它不那么便携。

我的答案是:

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

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