LookIntoEast
LookIntoEast

Reputation: 8798

How to turn list into string in bash?

One silly question:

What I have now:

NA06994.del.vcf
NA07048.del.vcf
NA07056.del.vcf
NA11892.del.vcf
NA11893.del.vcf
NA12003.del.vcf
NA12043.del.vcf

How to turn into:

NA06994.del.vcf NA07048.del.vcf NA07056.del.vcf NA11892.del.vcf NA11893.del.vcf...

Upvotes: 2

Views: 252

Answers (3)

mklement0
mklement0

Reputation: 437238

Given this question's generic title, here's how the solutions below generalize:

  • The paste and tr solutions work with single-character separators only.
  • The awk solution can work with any character sequence (string).

This answer points to the simplest solution that also avoids a trailing space: paste -s:

paste -sd ' ' file
  • -d ' ' tells paste to use a single space as the delimiter (separator)

  • -s concatenates the lines of the input file using the specified separator between lines, but not after the last one.


An awk solution that avoids a trailing space in the output:

awk '{ printf "%s%s", sep, $0 } NR==1 { sep = " " } END { printf "\n" }' file

(The commands would also work without NR==1, yet less efficiently so, although it may not matter in the real world:
awk '{ printf "%s%s", sep, $0; sep = " " }' file)

  • Uninitialized variables in awk default to the empty string in a string context, so sep is initially empty.
    • Thus, for the first line, string concatenation sep $0 is effectively the same as just $0, the input line.
  • NR==1 { sep = " " } sets variable sep to a single space, if the current line number (NR) is 1. Thus, starting with line 2, sep will be a single space, so that a single space is prepended to each subsequent input line on output.

The net effect is that a space is only inserted between input lines, but not at the end.
Omit END { printf "\n" } if you don't want a trailing newline.


A simple alternative using tr, assuming a trailing space is not a problem:

tr '\n' ' ' < file

Note that no trailing newline is output.

If you do need to remove the trailing space,

  • with GNU head:

    tr '\n' ' ' < file | head -c -1

  • otherwise, using shell parameter expansion:

    str=$(tr '\n' ' ' < file) str=${str% } printf %s "$str" # use '%s\n' to output a trailing newline

Upvotes: 0

Tom Fenech
Tom Fenech

Reputation: 74595

Using awk, you can set the output record separator ORS to a space:

awk -v ORS=' ' '1' file

By default, the input record separator is a newline. This is removed by awk and replaced with ORS (a newline by default) when you use print. The script 1 is the shortest true condition, which triggers the default action { print }.

It's marginally longer than using echo with cat but there are a number of advantages to this approach.

Firstly, white space in your file is preserved. This is because when you pass the result of cat to echo, it only sees the words in the file as a list of arguments, which it prints separated by a single space.

Secondly, there are no issues with special characters in your file, such as *, which would be glob-expanded by the shell before being passed to echo.

Thirdly, this all happens in a single process rather than making use of a subshell.

Upvotes: 2

Jeff Puckett
Jeff Puckett

Reputation: 40861

let's say that file named a has these contents:

NA06994.del.vcf
NA07048.del.vcf
NA07056.del.vcf
NA11892.del.vcf
NA11893.del.vcf
NA12003.del.vcf
NA12043.del.vcf

then, this command in bash will do what you want:

echo `cat a`

will result in this output:

NA06994.del.vcf NA07048.del.vcf NA07056.del.vcf NA11892.del.vcf NA11893.del.vcf NA12003.del.vcf NA12043.del.vcf

Upvotes: 0

Related Questions