How do I join the result of ls -1
into a single line and delimit it with whatever I want?
22 Answers
paste -s -d
joins lines with a delimiter (e.g. ","
), and does not leave a trailing delimiter:
ls -1 | paste -sd "," -

- 24,552
- 19
- 101
- 135

- 8,614
- 1
- 15
- 2
-
35Just as a note, the version of paste I tried requires a "-" argument at the end to tell it to read from STDIN. e.g. `ls -1 | paste -s -d ":" -` Not sure if that's universal with all versions of paste – Andy White May 10 '12 at 16:15
-
5this one is better because it allows empty delimiter :) – iururu Aug 15 '14 at 23:05
-
2Note `paste` gets `-` (standard input) as default, at least on my `paste (GNU coreutils) 8.22`. – fedorqui Jul 29 '15 at 13:19
-
2i just upvoted it, this is and now it has the same votes as the selected answer. THIS IS THE ANSWER. no trailing delimeter – thebugfinder Sep 14 '15 at 13:23
-
1The empty delimiter can be specified using `"\0"`, so `paste -sd "\0" -` worked for me! – Brad Parks Dec 17 '15 at 20:08
-
1@BradParks, what's wrong with just `paste -sd "" -`? – Vedran Šego Dec 01 '18 at 12:30
-
@iururu not if it's empty – theonlygusti Nov 11 '22 at 01:27
-
How can I do it with no delimiter? – theonlygusti Nov 11 '22 at 01:27
-
1This way, the delimiter can only be a single character. – Константин Ван Feb 14 '23 at 05:47
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)

- 62,887
- 36
- 269
- 388

- 22,776
- 12
- 65
- 95
-
50
-
6
-
@unicornaddict you can use -b or -q for ls to handle strange cases like you mention. – zaf May 04 '10 at 09:40
-
-
@mouviciel: You can just append a "\n" at the end, with say, `ls -1 | tr "\\n" ","; echo` – ShreevatsaR Oct 17 '11 at 07:03
-
3@ShreevatsaR: he means to not append a trailing "," I believe. like so `ls -1 | tr "\\n" "," | sed 's/\(.*\),/\1/'` – Chris Mar 08 '12 at 20:21
-
7@Chris: your `sed` could be a little more efficient with the end-marker character: `ls -1 | tr "\\n" "," | sed 's/,$//'; echo ''` – pieman72 Dec 17 '13 at 01:21
-
-
-
@ElgsQianChen I suppose you can. Add another comma in the command. Have you tried it? – zaf Dec 18 '16 at 09:38
-
`ls | paste -sd, -` is the best way to do it - no need to worry about the trailing comma. No need for `-1` in `ls` because it is implied when the output is not going to the terminal. – codeforester Nov 03 '18 at 02:46
-
6Using `sed` after `tr` seems just to remove last symbol seems unreasonable. I go with `ls -1 | tr '\n' ',' | head -c -1` – reddot Mar 08 '19 at 08:02
-
This almost works, but as many mentioned, leaves the trailing comma. What worked for me in keeping with the simplicity: `ls -1 | xargs | tr " " ","` – Rudi Strydom Mar 09 '21 at 11:22
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.

- 346,391
- 90
- 374
- 439
-
This will not take care of files with white spaces in the name. Try this one: dir=/tmp/testdir; rm -rf $dir && mkdir $dir && cd /$dir && touch "this is a file" this_is_another_file && ls -1 && files=($(ls -1)) && list=${files[@]/%/,} && list=${list%*,} && echo $list – dimir Oct 23 '14 at 13:55
-
1@dimir: Many of the answers to this question suffer from this problem. I have edited my answer to allow for filenames with tabs or spaces, but not newlines. – Dennis Williamson Oct 23 '14 at 15:58
-
Your bash version suffers from pathname expansions too. To build an array from lines, please consider using `mapfile` (Bash ≥4) as: `mapfile -t files < <(ls -1)`. No need to fiddle with `IFS`. And it's shorter too. – gniourf_gniourf Oct 23 '14 at 16:08
-
And when you have your array, you can use `IFS` to join the fields: `saveIFS=$IFS; IFS=,; list=${files[*]}; IFS=$saveIFS`. Or use another method if you want a separator with more that one character. – gniourf_gniourf Oct 23 '14 at 16:10
-
Also, your concatenation `list=${files[@]/%/,}` will not quite work as expected, as you'll also get the first character of `IFS` after the commas (very likely a space). Sorry for the many comments, but there are a few things to fix here! – gniourf_gniourf Oct 23 '14 at 16:14
-
1@gniourf_gniourf: I have included your suggestions in my answer. Thanks. – Dennis Williamson Oct 23 '14 at 16:38
-
A simple `files=(*)` will work fine. Also, a delayed evaluation of `*` will avoid playing around with IFS: `IFS=, command eval 'list=${files[*]}'; echo "<$list>"`. Of course, `IFS=, command eval echo '"${files[*]}"'` is shorter, but doesn't set `$list` variable string. – Jan 31 '17 at 20:14
-
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.

- 62,887
- 36
- 269
- 388

- 8,730
- 9
- 54
- 72
-
13
-
7This is especially awesome due to handling multi-character record separators (e.g., `" OR "`) – Mat Schaffer Nov 16 '16 at 07:02
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.
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 "$*")

- 238,783
- 38
- 220
- 352
-
2Do you have some more information regarding how `set` works? Looks a bit like voodoo to me. shallow look through `man set` didn't net me much information either. – Ehtesh Choudhury Sep 12 '13 at 18:08
-
3If you give `set` a bunch of arguments but no options, it sets the positional parameters ($1, $2, ...). `--` is there to protect `set` in case the first argument (or filename in this case) happens to start with a dash. See the description of the `--` option in `help set`. I find the positional parameters a convenient way to handle a list of things. I could also have implemented this with an array: `output=$( files=(*); IFS=,; echo "${files[*]}" )` – glenn jackman Sep 12 '13 at 18:16
-
This is great since it doesn't require executing any additional programs and it works with file names that contain spaces or even newlines. – Eric Jan 21 '15 at 22:26
-
1@EhteshChoudhury As `type set` will tell you, `set is a shell builtin`. So, `man set` will not help, but `help set` will do. Answer: "-- Assign any remaining arguments to the positional parameters." – Stéphane Gourichon Mar 30 '16 at 15:01
-
After a `set -- *`. Delaying expansion of `*` one level you may get the correct output without the need of a sub shell: `IFS=',' eval echo '"$*"'`. Of course that will change the positional parameters. – Jan 31 '17 at 20:01
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"

- 1,350
- 1
- 22
- 29
-
1Note: negative byte counts are only supported on certain versions of head, so this won't work on e.g. macos. – Peter Feb 04 '19 at 22:09
-
Thanks, for pointing that out. I have added a workaround for MacOS. – Aleksander Stelmaczonek Feb 06 '19 at 10:47
Don't reinvent the wheel.
ls -m
It does exactly that.

- 2,559
- 2
- 20
- 33
-
The OP wanted any delimiter so you would still need a tr to convert the commas. It also adds a space after the commas i.e. file1, file2, file3 – rob Apr 26 '13 at 08:50
-
so using `ls -m` and `tr` to remove the space after the comma you would do `ls -m | tr -d ' '` – Andrew Apr 30 '13 at 12:33
-
2that use of tr will delete spaces inside filenames. better to use `sed 's/, /,/g` – glenn jackman May 07 '13 at 10:45
just bash
mystring=$(printf "%s|" *)
echo ${mystring%|}

- 327,991
- 56
- 259
- 343
-
5Slightly more efficient would be to use "printf -v mystring "%s|" *" - that avoids a fork for the $() – camh May 09 '10 at 09:56
-
-
1
-
@camh But `printf -v` will work only in bash, while the presented answer works on many shell types. – Jan 31 '17 at 21:28
-
@Christopher Yes, that will remove the trailing `|`, provided that both lines are used: `printf -v mystring "%s|" * ; echo ${mystring%|}`. – Jan 31 '17 at 21:30
-
-
@sorontar The question is tagged "bash" and the answer my comment is on says "just bash". So why would I avoid bash? – camh Feb 01 '17 at 10:04
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 ' '

- 2,191
- 2
- 17
- 16
To avoid potential newline confusion for tr we could add the -b flag to ls:
ls -1b | tr '\n' ';'

- 61
- 1
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)
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

- 3,114
- 2
- 13
- 7
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.

- 54,589
- 14
- 104
- 138

- 827
- 8
- 5
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.

- 9,164
- 7
- 40
- 39
-
3`-d` specifies the input delimiter with GNU xargs, so will not work. The second example exhibits the same issue as other solutions here of a stray delimiter at the end. – Thor Sep 13 '12 at 15:09
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'

- 45,082
- 11
- 119
- 130
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())"

- 73
- 4
-
I can't believe a Python oneliner is the best way I can find for a multicharacter delimiter... but it is: `python -c "import sys; print(' | '.join(sys.stdin.read().splitlines()))"`. POSIX failed me again. – Ciro Santilli OurBigBook.com Aug 02 '22 at 17:22
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()))"

- 29
- 1
-
I don't know why the OP wants to do it, but I know why I need to do it: in order to copy all the filenames separated by a space to use them as parameters for rubocop, eslint, stylelint, haml-lint, etc. – cmoran92 Aug 29 '20 at 22:41
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.

- 3,733
- 1
- 35
- 36
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.

- 476
- 5
- 7
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

- 129
- 1
- 2