The GNU implementation of ls has a --quoting-style options which let you specify a quoting style, but none of them is compatible with the quoting style expected by xargs.
xargs (introduced by PWB Unix in the late 70s) quoting style is similar to that of the Mashey shell (also from PWB Unix), a predecessor of the Bourne shell.
ls --quoting-style=shell-always quotes with single quotes as per the Bourne/POSIX shell style, with single quotes themselves entered as \'. xargs supports both '...' and "..." in addition to backslash but quoted strings cannot include newline characters which can only be escaped with backslash.
The POSIX xargs specification also expects xargs to parse the input as text in the current locale and also does not guarantee it will work for arguments larger than 256 bytes, so in general can't be used to process arbitrary data.
The really only reliable way to use xargs is with the -0 option found in some implementations such as GNU xargs (you also generally want to use the -r option, also non-standard).
The next version of GNU ls will have a --zero option to output files NUL-delimited, so then you'll be able to do:
ls -t --zero | xargs -r0 printf ' * %s\n'
For instance.
For now, what you can do is use the --quoting-style=shell-always mode to pass that list to a shell, and that shell to convert it to a NUL-delimited list:
(
echo 'files=('
ls --quoting-style=shell-always -t
echo '); print -rNC1 -- $files'
) | zsh | xargs -r0 some command
But if you're already using zsh, you don't really need ls nor xargs as zsh can sort its globs by other criteria like ls and has a stat builtin to retrieve file metadata (the only reasons you may want to use ls) and its own zargs command.
In any case, in:
ls -d -- *.txt
It's the shell that expands *.txt to the list of matching files. ls is pretty useless there as it just ends up printing them.
You might as well pass the glob expansion to something that can print the list NUL-delimited, such as the print builtin in zsh:
print -rNC1 -- *.txt(N)
(here also using the Nullglob qualifier, so it prints nothing if the glob doesn't match any file).
Or in the bash shell (sometimes still used on GNU systems as that's the GNU shell):
print0() {
[ "$#" -eq 0 ] || printf '%s\0' "$@"
}
shopt -s nullglob
print0 *.txt
rm -rf 2021*/"X y"/foobar– muru Dec 19 '21 at 09:15