(trap : INT; echo "$(less <<< 'some text' >/dev/tty; echo done)")
less
превратится в своего рода (un )причудливый cat
, когда его стандартный вывод не является tty, как при использовании в подстановке команды (, где его стандартный вывод является каналом)[1].
При тестировании в интерактивном bash (, где управление заданиями включено по умолчанию ), подоболочка (...)
гарантирует, что команда less
выполняется как часть надлежащего приоритетного задания в терминал, без которого может быть невозможно приостановить его с помощью ^Z
, завершить его с помощью ^C
и другими способами [2].
trap : INT
заставит подоболочку игнорировать ^C
, не передавая это расположение своим потомкам.
Если команда является частью сценария оболочки, все процессы будут выполняться как часть одной и той же группы процессов/задания, но (...)
все же может быть полезно для ограничения области ловушки INT
.
[1] Вы даже не можете использовать его для вывода двоичных данных с красивым экранированием, если его стандартный вывод не является tty:
$ printf '\xee' | less -FXR
<EE>
$ printf '\xee' | less -FXR | cat
�$
[2] Есть много возможных сценариев того, что может произойти, и все они плохие. Например, в
$ ls -d $(less <<<'some text' >/dev/tty; pwd)
bash
разветвит отдельный процесс, в котором будет выполняться двоичный файл ls
, и запустит подстановку процесса $(...)
в качестве его дочернего элемента , прежде чем переместит его в отдельную группу процессов/задание и выполнит двоичный файл.
Когда вы нажимаете ^Z
внутри less
, он будет обработан less
как обычно, но либо не сможет остановить его (, если оболочка и, следовательно, работа less
является лидером сеанса ), или вызовет остановку только less
, но не его родительского процесса.
Когда вы нажмете ^C
внутри less
, он будет пойман и обработан less
,но SIGINT
также будет отправлено в основную оболочку (, которая является приоритетным заданием на терминале ), что заставит его вернуть следующее приглашение, а строка чтения bash и less
будут конкурировать за ввод и изменяют свойства терминала, не подозревая друг о друге, что приводит к полной лаже.
Примечание
Все это относится к любой программе, запускаемой из подстановки команд, а не только к $(less...)
примеру, например.
$ cat >foo <<'EOT'; chmod 755 foo
t=$(mktemp)
vi "$t" </dev/tty >/dev/tty 2>&1
echo "$t"
EOT
$ cat $(./foo)
# ^Z doesn't work in vi
Если оставить $(ls -tr)
без кавычек, вызовет split+glob после раскрытия.
Разделение выполняется на основе символов$IFS
(по умолчанию SPC, TAB и NL ), а затем часть glob будет искать там подстановочные знаки и пытаться расширить файлы, соответствующие соответствующим шаблонам.
Здесь похоже, что вы на самом деле хотите разделить вывод ls
только на NL-символы и не выполнять часть glob. Так и должно быть:
IFS=$'\n' # split on NL only
set -o noglob # disable the glob part
for f in $(ls -tr); do
printf '%s\n' "$f"
done
Тогда это будет работать нормально для ваших файлов, содержащих символы SPC. Однако это все равно не будет работать, если есть имена файлов с символами NL.
Здесь лучше всего переключиться на zsh
и выполнить:
for f in *(NOm); do
printf '%s\n' "$f"
done
Где *
заменяется на все не -скрытые файлы в текущем каталоге, отсортированные в обратном порядке по возрасту, как ls -rt
с квалификатором Om
glob (N
один (дляnullglob
)позволяет избежать ошибки, если нет соответствующего файла ).
Или, если у вас GNU ls
, сbash
:
eval "files=($(ls --quoting-style=shell-always -rt))"
for f in "${files[@]}"; do
printf '%s\n' "$f"
done