24

ls prints differently depending on whether the output is to a terminal or to something else.

e.g.:

$ ls .
file1  file2
$ ls . | head
file1
file2

Is there some way to make ls print out on one line as if it's to a terminal when it's not. There's a -C argument that sorta does that, but it will split it into several lines.

$ ls
file1  file10  file11  file12  file13  file14  file15  file16  file17  file18  file19 file2  file3  file4  file5  file6  file7  file8  file9
$ ls -C . | head
file1 file11 file13 file15 file17 file19 file3  file5  file7  file9
file10 file12 file14 file16 file18 file2 file4  file6  file8

The reason I want to do this is that I want to monitor the files in a directory that were changing quickly. I had constructed this simple command line:

while [[ true ]] ; do ls ; done | uniq

The uniq prevents it from spamming my terminal and only showing changes. However it was printing it all on differnet lines, which was making the uniq useless, and increasing the amount of noise. In theory one could use watch for this, but I wanted to see a file as soon as it appeared/disappeared.

This is the final solution:

while [[ true ]] ; do ls | tr '\n' ' ' ; done | uniq
2
  • 4
    if you are piping ls to another command, you are doing something wrong. What are you actually trying to accomplish?
    – Justin
    Jan 24, 2010 at 16:01
  • Justin, I have updated the question with an explaination. Jan 25, 2010 at 10:30

9 Answers 9

27

i don't know of a switch which could do that, but you can pipe your output through tr to do it:

ls | tr "\n" " " | <whatever you like>
30
ls | xargs

It works for me, it's the simplest way I've found ever. Hope this helps you as well.

5

If your ls has this option, you can use a high value and it might do what you want:

ls -w 10000 -C . | head
5

What about the quite trivial

echo *

? :-) You don't need even to fork for it. :-)

4

ah, now that you've updated the question....

while true ; do echo * ; done | uniq

will do what you posted, just simpler.

however, you are better off using something that uses inotify to do this.. like

inotifywait -m . -e create,delete

if you don't have inotify, then something like this works well too:

import os
import time

last = set()
while True:
    cur = set(os.listdir('.'))
    added = cur-last
    removed = last-cur
    if added: print 'added', added
    if removed: print 'removed', removed
    last = set(os.listdir('.'))
    time.sleep(0.1)
2
ls -xw0

From man ls:

-w, --width=COLS
       set output width to COLS.  0 means no limit

-x     list entries by lines instead of by columns
1

You can use back ticks in the shell to achieve this like:

echo -E `ls -1`
2
  • Doesn't work with all file names. Try: touch ./-en
    – kasperd
    Jan 28, 2017 at 6:45
  • That only matters if you have no files starting with [a-d] that sort before it. If you're running it in a script echo -E wouldn't be too inconvenient and the trailing newline may not matter.
    – chicks
    Jan 28, 2017 at 18:47
0

This may be what you are looking for but I may have misunderstood your question but here goes :)

A few commands worth looking into:

watch - execute a program periodically, showing output fullscreen xargs - build and execute command lines from standard input (-0 if you want to handle files with spaces etc)

You can do something like the following to show the last 10 files/dirs that changed with a 2 second interval (default for watch)

watch "ls -lart | tail -10"

the options -lart tell ls to be verbose and sort based on modification time.

If you really just want the files I would just do something like:

watch "ls -lart | awk '{print \$8}' | tail -10 | xargs"

or just to display them:

ls -lart | awk '{print $8}' | tail -10 | xargs

0

This worked for me because I needed not only to print the result in one line but also I needed to specify how it had to be separated and you can specify that with ORS

ls -1 | awk '{ ORS="|"; print; }'

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .