filename ... dangerous to eval
$ touch 'file $(date >&2).txt'
$ bash -c 'eval ls *'
Wed 03 Feb 2021 06:07:08 PM EET
ls: cannot access 'file': No such file or directory
ls: cannot access '.txt': No such file or directory
or backtick the output of ls in a bash script?
I'm not exactly sure what this means.
If you mean what you had as an example,
or with a saner syntax,
files=( $(ls -t) )
then you just the get the output of
ls wordsplit to the array.
$ declare -p files
declare -a files=(="file" ="\$(date" =">&2).txt")
The biggest problem here, even before the possible command injection, is that the space in the filename broke it, we got two array entries instead of one. See the page about parsing ls on Greg's wiki. No, you can't work around it by adding quotes, word splitting doesn't work like that.
So, don't use
ls there. Just let the shell generate the list of filenames:
declare -p files
declare -a files=(="file \$(date >&2).txt")
The only problem here, is that Bash doesn't give a good way of sorting files by their date, so
ls -t is tempting. The good alternatives are to put the date in the filename itself so the default sorting gives you sorting by date, or to use Zsh, since it can sort by date. Or do ugly hacks to work around the issue (caveat, I haven't tested that solution).
The same problem with
eval comes if you need to pass the filename to anything that takes just a shell script, like
ssh somehost "do something with $file" # wrong
ssh somehost "do something with '$file'" # still wrong, the name
# could contain single ticks
It seems like the filesystem sanitizes special characters, spaces for instance, by wrapping the filenames in quotes. Will it catch all such things?
Oh dear, oh no it doesn't. If the filesystem did something to prevent storing special characters to the shell, half of the posts on unix.SE wouldn't be needed.
If you want the pain that comes from too much knowledge, here's an essay by David Wheeler about that: Fixing Unix/Linux/POSIX Filenames:
Control Characters (such as Newline), Leading Dashes, and Other Problems
There's also the other one by him, Filenames and Pathnames in Shell: How to do it Correctly. Lots of the subject matter of that has also been discussed here on unix.SE.
Also, quotes don't even help.
$ touch '"quoted name"' 'othername' # two files
$ printf "%s\n" $(ls) # oops
$ printf "%s\n" * # this works better
Because when word splitting happens, quotes are just a regular character. (Unless you set
IFS to include quotes, which probably just makes it worse.) Besides, even if the name is wrapped in quotes, it could still have quotes in the middle, breaking that. You'd need to take care the escape or quote those correctly, too.
It's GNU ls that does the quoting, depending on version and settings:
$ ls -l
-rw-rw-r-- 1 ilkkachu ilkkachu 0 Feb 3 18:30 othername
-rw-rw-r-- 1 ilkkachu ilkkachu 0 Feb 3 18:30 '"quoted name"'
That's the same as
ls --quoting-style=shell. Incidentally, it seems to get it right, for all of newlines, dollar signs, and quotes. But do you trust it to get it right? If you do, and you know how to use it correctly, you may be able to use it to get the sorted listing.