The output file is created by the shell before ls
begins. You can get around this by using tee
:
ls | tee list
To thoroughly defeat any race condition, there is always
ls | grep -vx 'list' > list
Or if you like that tee
displays the results as well:
ls | grep -vx 'list' | tee list
However, as pointed out in comments, things like this often break when filenames contain strange characters. Unix filenames can generally contain any characters except for NUL
and /
, so parsing the output of ls
is extremely difficult:
- Assigning to a shell variable can fail if a filename ends in one or more
\n
.
- Filtering with
grep
fails when the search term lies between \n
.
- You can separate filenames with
NUL
instead of \n
using find
, but it can be difficult to convert this into something resembling the traditional sorted, newline-separated output of ls
.
- Removing the output filename from the list may be incorrect if it already exists.
So the only truly effective way to do this is to create the output file somewhere else, and move it into place. If you will never use ls -a
, then this works:
ls > .list && mv .list list
If you might be using ls -a
, then .list
could appear in your output but no longer exist in the directory. So then you would use a different directory, like /tmp
to store the intermediate result. Of course, if you always use /tmp
you run into trouble there, so you can write a script:
#!/bin/sh
OUTDIR='/tmp'
if [ "${PWD}" = '/tmp' ]; then
OUTDIR="${HOME}"
fi
ls > "${OUTDIR}/list" && mv "${OUTDIR}/list" list
This seems overly complicated for the task, though.
But the entire cause of the issue is that the shell is creating the output file before the command begins. We can take that into consideration and just have the shell list the files for us. Then we don't even need ls
at all!
printf '%s\n' * > list
This will work until you have too many files in the directory to fit into an argument list.
echo \
ls` > ls` which I love for being so concise, but this doesnt put an entry on each line which my particular situation has issues with (as I very much do need to deal with directories with spaces in them today)... – Steven Lu Jul 16 '16 at 00:17ls -1
will force single-column output – Stephen Harris Jul 16 '16 at 00:21echo "$(ls -1)" > file
? – Steven Lu Jul 16 '16 at 00:21ls
and the file creation into two steps. Also beware ofecho
potentially interpreting the output of thels
; (what if you have a file called-ne
?). That's why I usedprintf
in my example. – Stephen Harris Jul 16 '16 at 00:24x=$(ls)
removes all the trailing newline characters from the output ofls
while yourprintf '%s\n'
adds only one back. – Stéphane Chazelas Jul 16 '16 at 10:36echo "`ls`" > ls
orecho "$(ls)"
. – Jonathan Leffler Jul 16 '16 at 14:07$(ls)
is evaluated before the redirection>file
. The reason you aren't getting one file per line is that you didn't use double quotes:echo "$(ls)" >file
– Gilles 'SO- stop being evil' Jul 16 '16 at 20:28