In ls *.fits
, it's the shell that does all the hard work finding the filenames that end in .fits
and don't start with .
.
Then it passes that list to ls
, which sorts it (again, as shell globs already sort the list before passing to ls
) and displays it (in columns or one per line depending on the implementation and whether the output goes to a terminal or not) after having checked that each file exists.
So it's a bit counter-productive especially considering that:
- you forgot the
--
option delimiter, so any filename starting with -
would cause problems.
- you forgot the
-d
option, so if any file is of type directory, ls
would list their contents instead of themselves.
- as
ls
is a separate command from the shell (in most shells including bash
), it ends up having to be executed in a separate process using the execve()
system call and you end-up tripping its limit on the cumulative size of arguments and environment variables.
If you just need to print the list generated by the shell from *.fits
, you can use printf
instead which is built-in in most shells (and therefore doesn't invoke execve()
and its limit):
printf '%s\n' *.fits > output_all.txt
That leaves one problem though:
If *.fits
doesn't match any file, in the bash
shell, *.fits
is left as-is, so printf
will end-up printing *.fits<newline>
.
While ls
would give you an error message about that non-existent *.fits
file and leave the output_all.txt
empty.
That can be changed with the nullglob
option (which bash copied from zsh
) which causes *.fits
to expand to nothing instead. But then we run into another problem: when not passed any argument beside the format, printf
still goes through the format once as if passed empty arguments, so you'd end up with one empty line in output_all.txt
.
That one can be worked around with:
shopt -s nullglob
println() {
[ "$#" -eq 0 ] || printf '%s\n' "$@"
}
println *.fits > output_all.txt
If you can switch to zsh
instead of bash
, it becomes easier:
print -rC1 -- *.fits(N) > output_all.txt
Where N
enables nullglob
for that one glob and print -rC1
prints its arguments r
aw on 1
C
olumn, and importantly here: prints nothing if not passed any argument.
With zsh
, you can also restrict the list to regular files only (excluding directories, symlinks, fifos..) using the .
glob qualifier (*.fits(N.)
for instance), or include hidden files with D
(*.fits(ND.)
)...
Lastly you can also always defer to find
to find the files, but if you do need the list to be sorted and hidden files to be excluded, and avoid a ./
prefix, that becomes quickly tedious as well and you'd need GNU extensions. For example, for the equivalent of print -rC1 -- *.fits(N.)
:
LC_ALL=C find . -maxdepth 1 ! -name '.*' -type f -printf '%P\0' |
sort -z | tr '\0' '\n' > output_all.txt
ls | grep .fits$ > output_all.txt
work? – Bib Nov 26 '21 at 15:45