Concise and portable “join” on the Unix command-li

2019-01-06 12:35发布

How can I join multiple lines into one line, with a separator where the new-line characters were, and avoiding a trailing separator and, optionally, ignoring empty lines?

Example. Consider a text file, foo.txt, with three lines:

foo
bar
baz

The desired output is:

foo,bar,baz

The command I'm using now:

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

Ideally it would be something like this:

cat foo.txt |join ,

What's:

  1. the most portable, concise, readable way.
  2. the most concise way using non-standard unix tools.

Of course I could write something, or just use an alias. But I'm interested to know the options.

标签: shell unix
9条回答
倾城 Initia
2楼-- · 2019-01-06 13:04

How about to use xargs?

for your case

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

Be careful about the limit length of input of xargs command. (This means very long input file cannot be handled by this.)

查看更多
啃猪蹄的小仙女
3楼-- · 2019-01-06 13:07

Perhaps a little surprisingly, paste is a good way to do this:

paste -s -d","

This won't deal with the empty lines you mentioned. For that, pipe your text through grep, first:

grep -v '^$' | paste -s -d"," -
查看更多
疯言疯语
4楼-- · 2019-01-06 13:11

Perl:

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

or yet shorter and faster, surprisingly:

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

or, if you want:

cat data.txt | perl -pe 's/\n/,/ unless eof'
查看更多
我命由我不由天
5楼-- · 2019-01-06 13:13

My answer is:

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

printf is enough. We don't need -F"\n" to change field separator.

查看更多
不美不萌又怎样
6楼-- · 2019-01-06 13:14

I needed to accomplish something similar, printing a comma-separated list of fields from a file, and was happy with piping STDOUT to xargs and ruby, like so:

cat data.txt | cut -f 16 -d ' ' | grep -o "\d\+" | xargs ruby -e "puts ARGV.join(', ')"
查看更多
仙女界的扛把子
7楼-- · 2019-01-06 13:22

Just for fun, here's an all-builtins solution

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

You can use printf instead of echo if the trailing newline is a problem.

This works by setting IFS, the delimiters that read will split on, to just newline and not other whitespace, then telling read to not stop reading until it reaches a nul, instead of the newline it usually uses, and to add each item read into the array (-a) data. Then, in a subshell so as not to clobber the IFS of the interactive shell, we set IFS to , and expand the array with *, which delimits each item in the array with the first character in IFS

查看更多
登录 后发表回答