Bash for loop over ls разбивает строку на символе " ("

(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
0
27.10.2020, 22:41
1 ответ

Если оставить $(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с квалификатором Omglob (Nодин (дляnullglob)позволяет избежать ошибки, если нет соответствующего файла ).

Или, если у вас GNU ls, сbash:

eval "files=($(ls --quoting-style=shell-always -rt))"
for f in "${files[@]}"; do
  printf '%s\n' "$f"
done
5
18.03.2021, 22:54

Теги

Похожие вопросы