335

I'm using ls -a command to get the file names in a directory, but the output is in a single line.

Like this:

.  ..  .bash_history  .ssh  updater_error_log.txt

I need a built-in alternative to get filenames, each on a new line, like this:

.  
..  
.bash_history  
.ssh  
updater_error_log.txt
MultiplyByZer0
  • 6,302
  • 3
  • 32
  • 48
fixxxer
  • 15,568
  • 15
  • 58
  • 76
  • 3
    ls is intended to display a list for human consumption. If you are using ls for any other purpose (like, say, to get a list of files in a script to iterate over), you are most certainly using the wrong tool. – Juliano Oct 07 '10 at 22:29
  • 4
    @juliano - It is to be consumed by a python script actually. Why do you call it a wrong tool? – fixxxer Oct 07 '10 at 22:33
  • 2
    @fixxer The moment you pipe `ls` to python, `ls` will output one file per line as I explained in my answer. – Peter G. Oct 07 '10 at 22:37
  • 7
    @fixxxer: Then you are indeed using it wrongly. It formats the listing for output in the user terminal. It may replace special characters in the filename, it may omit characters that have special meaning, etc... In other words, ls *formats* a list to the user. You want unformatted filenames. Any special reason that you are not using the python 'glob' module? http://docs.python.org/library/glob.html There are also 'fnmatch', 'dircache' and others. – Juliano Oct 07 '10 at 22:38
  • 1
    @fixxer Have you actually made `ls` to output to `python` and observed the single-line output in python? – Peter G. Oct 07 '10 at 22:48
  • @juliano I'm connected via SSH to the remote machine. I'm finding no way to execute a python function like os.listdir on the remote machine in a single line. Hence, this question. I don't want to write a script for simply listing files. Is there anyother way around it? – fixxxer Oct 11 '10 at 20:30
  • @fixxxer without more information, it is hard to tell. Perhaps if you give a better description of what is the end-result you expect. If you need a list of filenames, `find` is much more appropriate than `ls`. – Juliano Oct 11 '10 at 22:20

8 Answers8

618

Use the -1 option (note this is a "one" digit, not a lowercase letter "L"), like this:

ls -1a

First, though, make sure your ls supports -1. GNU coreutils (installed on standard Linux systems) and Solaris do; but if in doubt, use man ls or ls --help or check the documentation. E.g.:

$ man ls
...
       -1     list one file per line.  Avoid '\n' with -q or -b
MultiplyByZer0
  • 6,302
  • 3
  • 32
  • 48
Bert F
  • 85,407
  • 12
  • 106
  • 123
  • 4
    +1 I didn't know about -1 (-l yes (ell not one)) It shows in the man-page but I've been reading it as an ell the whole time :) – slashmais Oct 07 '10 at 22:49
  • @slashmais - Ah, good point - easy to mistake. I clarified in the answer. – Bert F Oct 07 '10 at 23:01
  • 1
    @dty: for GNU, you get this documented in `ls --help` output... always installed ;-) – Tony Delroy Oct 08 '10 at 05:03
  • @dty: ok... but enough systems lack the man and/or info pages, so it didn't read that way :-). – Tony Delroy Oct 08 '10 at 09:09
  • 3
    Searched on Google for `linux ls one file per line` and this was the top article. Can't believe how wordy the chosen answer is or that this answer has fewer votes than the one that pipes to cat. `ls -1` ftw. – crantok May 21 '13 at 21:05
  • 8
    `ls` defaults to `-1` behavior when the output isn't connected to the terminal. – codeforester Apr 09 '18 at 16:52
  • Very useful and fast to copy a list of files for a spreadsheet or elsewhere instead of using pandas!! – sugab Mar 09 '22 at 07:08
160

Yes, you can easily make ls output one filename per line:

ls -a | cat

Explanation: The command ls senses if the output is to a terminal or to a file or pipe and adjusts accordingly.

So, if you pipe ls -a to python it should work without any special measures.

Peter G.
  • 14,786
  • 7
  • 57
  • 75
34

Ls is designed for human consumption, and you should not parse its output.

In shell scripts, there are a few cases where parsing the output of ls does work is the simplest way of achieving the desired effect. Since ls might mangle non-ASCII and control characters in file names, these cases are a subset of those that do not require obtaining a file name from ls.

In python, there is absolutely no reason to invoke ls. Python has all of ls's functionality built-in. Use os.listdir to list the contents of a directory and os.stat or os to obtain file metadata. Other functions in the os modules are likely to be relevant to your problem as well.


If you're accessing remote files over ssh, a reasonably robust way of listing file names is through sftp:

echo ls -1 | sftp remote-site:dir

This prints one file name per line, and unlike the ls utility, sftp does not mangle nonprintable characters. You will still not be able to reliably list directories where a file name contains a newline, but that's rarely done (remember this as a potential security issue, not a usability issue).

In python (beware that shell metacharacters must be escapes in remote_dir):

command_line = "echo ls -1 | sftp " + remote_site + ":" + remote_dir
remote_files = os.popen(command_line).read().split("\n")

For more complex interactions, look up sftp's batch mode in the documentation.

On some systems (Linux, Mac OS X, perhaps some other unices, but definitely not Windows), a different approach is to mount a remote filesystem through ssh with sshfs, and then work locally.

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
  • I'm connected via SSH to the remote machine. I found no way to execute a python function like os.listdir on the remote machine in a single line. Hence, this question. I don't want to write a script for simply listing files. Is there anyother way around this problem? – fixxxer Oct 11 '10 at 20:32
  • @fixxxer: ssh does change the situation, it's the sort of things you should have mentioned in your original question! I think sftp is appropriate for your use case. – Gilles 'SO- stop being evil' Oct 11 '10 at 23:09
  • I'm sorry for the confusion. Is there a way I can insert the password in the "command_line" as well? – fixxxer Oct 12 '10 at 23:15
  • @fixxxer: I don't know, the authors of ssh frown on passwords stored in plain text and tend not to make this easy. You should really set up key-based authentication (there are plenty of tutorials on the web and questions on http://superuser.com/ about this). – Gilles 'SO- stop being evil' Oct 12 '10 at 23:27
11

you can use ls -1

ls -l will also do the work

qdot
  • 6,195
  • 5
  • 44
  • 95
ILF
  • 133
  • 1
  • 4
  • 2
    The top answer already mentions the exact things you said. also the question specifically says ```ls -l``` should not be used. – DevX Nov 30 '19 at 17:10
10

You can also use ls -w1

This allows to set number of columns. From manpage of ls:

   -w, --width=COLS
          set output width to COLS.  0 means no limit
smihael
  • 863
  • 13
  • 29
4
ls | tr "" "\n"
wscourge
  • 10,657
  • 14
  • 59
  • 80
showkey
  • 482
  • 42
  • 140
  • 295
2

Easy, as long as your filenames don't include newlines:

find . -maxdepth 1

If you're piping this into another command, you should probably prefer to separate your filenames by null bytes, rather than newlines, since null bytes cannot occur in a filename (but newlines may):

find . -maxdepth 1 -print0

Printing that on a terminal will probably display as one line, because null bytes are not normally printed. Some programs may need a specific option to handle null-delimited input, such as sort's -z. Your own script similarly would need to account for this.

8bittree
  • 1,769
  • 2
  • 18
  • 25
0

-1 switch is the obvious way of doing it but just to mention, another option is using echo and a command substitution within a double quote which retains the white-spaces(here \n):

echo "$(ls)"

Also how ls command behaves is mentioned here:

If standard output is a terminal, the output is in columns (sorted vertically) and control characters are output as question marks; otherwise, the output is listed one per line and control characters are output as-is.

Now you see why redirecting or piping outputs one per line.

S.B
  • 13,077
  • 10
  • 22
  • 49