How to join multiple lines of file names into one with custom delimiter?

LinuxBashShellParsingMerge

Linux Problem Overview


I would like to join the result of ls -1 into one line and delimit it with whatever i want.

Are there any standard Linux commands I can use to achieve this?

Linux Solutions


Solution 1 - Linux

Similar to the very first option but omits the trailing delimiter

ls -1 | paste -sd "," -

Solution 2 - Linux

> EDIT: Simply "ls -m" If you want your delimiter to be a comma

Ah, the power and simplicity !

ls -1 | tr '\n' ','

Change the comma "," to whatever you want. Note that this includes a "trailing comma" (for lists that end with a newline)

Solution 3 - Linux

This replaces the last comma with a newline:

ls -1 | tr '\n' ',' | sed 's/,$/\n/'

ls -m includes newlines at the screen-width character (80th for example).

Mostly Bash (only ls is external):

saveIFS=$IFS; IFS=$'\n'
files=($(ls -1))
IFS=,
list=${files[*]}
IFS=$saveIFS

Using readarray (aka mapfile) in Bash 4:

readarray -t files < <(ls -1)
saveIFS=$IFS
IFS=,
list=${files[*]}
IFS=$saveIFS

Thanks to gniourf_gniourf for the suggestions.

Solution 4 - Linux

I think this one is awesome

ls -1 | awk 'ORS=","'

ORS is the "output record separator" so now your lines will be joined with a comma.

Solution 5 - Linux

Parsing ls in general is not advised, so alternative better way is to use find, for example:

find . -type f -print0 | tr '\0' ','

Or by using find and paste:

find . -type f | paste -d, -s

For general joining multiple lines (not related to file system), check: Concise and portable “join” on the Unix command-line.

Solution 6 - Linux

The combination of setting IFS and use of "$*" can do what you want. I'm using a subshell so I don't interfere with this shell's $IFS

(set -- *; IFS=,; echo "$*")

To capture the output,

output=$(set -- *; IFS=,; echo "$*")

Solution 7 - Linux

Adding on top of majkinetor's answer, here is the way of removing trailing delimiter(since I cannot just comment under his answer yet):

ls -1 | awk 'ORS=","' | head -c -1

Just remove as many trailing bytes as your delimiter counts for.

I like this approach because I can use multi character delimiters + other benefits of awk:

ls -1 | awk 'ORS=", "' | head -c -2

EDIT

As Peter has noticed, negative byte count is not supported in native MacOS version of head. This however can be easily fixed.

First, install coreutils. "The GNU Core Utilities are the basic file, shell and text manipulation utilities of the GNU operating system."

brew install coreutils

Commands also provided by MacOS are installed with the prefix "g". For example gls.

Once you have done this you can use ghead which has negative byte count, or better, make alias:

alias head="ghead"

Solution 8 - Linux

Don't reinvent the wheel.

ls -m

It does exactly that.

Solution 9 - Linux

just bash

mystring=$(printf "%s|" *)
echo ${mystring%|}

Solution 10 - Linux

This command is for the PERL fans :

ls -1 | perl -l40pe0

Here 40 is the octal ascii code for space.

-p will process line by line and print

-l will take care of replacing the trailing \n with the ascii character we provide.

-e is to inform PERL we are doing command line execution.

0 means that there is actually no command to execute.

perl -e0 is same as perl -e ' '

Solution 11 - Linux

To avoid potential newline confusion for tr we could add the -b flag to ls:

ls -1b | tr '\n' ';'

Solution 12 - Linux

It looks like the answers already exist.

If you want a, b, c format, use ls -m ( Tulains Córdova’s answer)

Or if you want a b c format, use ls | xargs (simpified version of Chris J’s answer)

Or if you want any other delimiter like |, use ls | paste -sd'|' (application of Artem’s answer)

Solution 13 - Linux

The sed way,

sed -e ':a; N; $!ba; s/\n/,/g'
  # :a         # label called 'a'
  # N          # append next line into Pattern Space (see info sed)
  # $!ba       # if it's the last line ($) do not (!) jump to (b) label :a (a) - break loop
  # s/\n/,/g   # any substitution you want

Note:

This is linear in complexity, substituting only once after all lines are appended into sed's Pattern Space.

@AnandRajaseka's answer, and some other similar answers, such as here, are O(n²), because sed has to do substitute every time a new line is appended into the Pattern Space.

To compare,

seq 1 100000 | sed ':a; N; $!ba; s/\n/,/g' | head -c 80
  # linear, in less than 0.1s
seq 1 100000 | sed ':a; /$/N; s/\n/,/; ta' | head -c 80
  # quadratic, hung

Solution 14 - Linux

sed -e :a -e '/$/N; s/\n/\\n/; ta' [filename]

Explanation:

-e - denotes a command to be executed
:a - is a label
/$/N - defines the scope of the match for the current and the (N)ext line
s/\n/\\n/; - replaces all EOL with \n
ta; - goto label a if the match is successful

Taken from my blog.

Solution 15 - Linux

If you version of xargs supports the -d flag then this should work

ls  | xargs -d, -L 1 echo

-d is the delimiter flag

If you do not have -d, then you can try the following

ls | xargs -I {} echo {}, | xargs echo

The first xargs allows you to specify your delimiter which is a comma in this example.

Solution 16 - Linux

You can use:

ls -1 | perl -pe 's/\n$/some_delimiter/'

Solution 17 - Linux

ls produces one column output when connected to a pipe, so the -1 is redundant.

Here's another perl answer using the builtin join function which doesn't leave a trailing delimiter:

ls | perl -F'\n' -0777 -anE 'say join ",", @F'

The obscure -0777 makes perl read all the input before running the program.

sed alternative that doesn't leave a trailing delimiter

ls | sed '$!s/$/,/' | tr -d '\n'

Solution 18 - Linux

ls has the option -m to delimit the output with ", " a comma and a space.

ls -m | tr -d ' ' | tr ',' ';'

piping this result to tr to remove either the space or the comma will allow you to pipe the result again to tr to replace the delimiter.

in my example i replace the delimiter , with the delimiter ;

replace ; with whatever one character delimiter you prefer since tr only accounts for the first character in the strings you pass in as arguments.

Solution 19 - Linux

You can use chomp to merge multiple line in single line:

perl -e 'while (<>) { if (/\$/ ) { chomp; } print ;}' bad0 >test

put line break condition in if statement.It can be special character or any delimiter.

Solution 20 - Linux

If Python3 is your cup of tea, you can do this (but please explain why you would?):

ls -1 | python -c "import sys; print(','.join(sys.stdin.read().splitlines()))"

Solution 21 - Linux

Python answer above is interesting, but the own language can even make the output nice:

> ls -1 | python -c "import sys; print(sys.stdin.read().splitlines())"

Solution 22 - Linux

Quick Perl version with trailing slash handling:

ls -1 | perl -E 'say join ", ", map {chomp; $_} <>'

To explain:

  • perl -E: execute Perl with features supports (say, ...)
  • say: print with a carrier return
  • join ", ", ARRAY_HERE: join an array with ", "
  • map {chomp; $_} ROWS: remove from each line the carrier return and return the result
  • <>: stdin, each line is a ROW, coupling with a map it will create an array of each ROW

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJavaRockyView Question on Stackoverflow
Solution 1 - LinuxArtemView Answer on Stackoverflow
Solution 2 - LinuxzafView Answer on Stackoverflow
Solution 3 - LinuxDennis WilliamsonView Answer on Stackoverflow
Solution 4 - LinuxmajkinetorView Answer on Stackoverflow
Solution 5 - LinuxkenorbView Answer on Stackoverflow
Solution 6 - Linuxglenn jackmanView Answer on Stackoverflow
Solution 7 - LinuxAleksander StelmaczonekView Answer on Stackoverflow
Solution 8 - LinuxTulains CórdovaView Answer on Stackoverflow
Solution 9 - Linuxghostdog74View Answer on Stackoverflow
Solution 10 - LinuxSidharth C. NadhanView Answer on Stackoverflow
Solution 11 - LinuxyabtView Answer on Stackoverflow
Solution 12 - LinuxplhnView Answer on Stackoverflow
Solution 13 - LinuxzhazhaView Answer on Stackoverflow
Solution 14 - LinuxAnand RajasekarView Answer on Stackoverflow
Solution 15 - LinuxChris JView Answer on Stackoverflow
Solution 16 - LinuxcodaddictView Answer on Stackoverflow
Solution 17 - LinuxThorView Answer on Stackoverflow
Solution 18 - LinuxAndrewView Answer on Stackoverflow
Solution 19 - LinuxSumanView Answer on Stackoverflow
Solution 20 - LinuxbrtknrView Answer on Stackoverflow
Solution 21 - LinuxJoel Franco GuzmánView Answer on Stackoverflow
Solution 22 - LinuxCelogeek SanView Answer on Stackoverflow