Механика этого синтаксиса оболочки: ${1:-$(</ dev / stdin)}

Я недавно столкнулся с этим действительно аккуратным синтаксисом, в контексте создания bash функции, которые могут принимать аргумент или поток из STDIN (т.е. могут быть переданы по каналу). На первый взгляд, я понимаю, что здесь происходит, но я хотел бы немного больше объяснить фактическую механику того, как это работает.

Вот синтаксис (согласно заголовку): ${1:-$(</dev/stdin)}

И в контексте можно использовать его как:

log(){
 echo -e >&1 "INFO: ${1:-$(</dev/stdin)}"
}

Разрешить следующее использование:

$ log foo
INFO: foo

В качестве альтернативы, вы также можете сделать это

mv -v foo.ext bar.ext | log
INFO: renamed 'foo.ext' -> 'bar.ext'

Это здорово, потому что это единственный лаконичный метод, который я видел для включения функций аргументов и конвейеров с bash функции (я забыл, где я столкнулся с этим сейчас, к сожалению).

Теперь я понимаю (или думаю, что понимаю) большую часть того, что происходит здесь, по крайней мере, поверхностно, но я был бы признателен за более глубокое понимание. Вот как я это понимаю, а затем мои оставшиеся вопросы:

${1:-$(</dev/stdin)}

  • ${1} очевидно, это аргумент по умолчанию, который принимает функция
  • ${1:-x} это расширение переменной / скобки 'отступить' к строке 'x' если $1 в противном случае пусто (или не установлено?). В этом случае возвращаемся к процессу STDIN.
  • $() очевидно, подстановка команды процесса
  • и наконец, </dev/stdin это, очевидно, перенаправление со стандартного ввода, которое позволяет каналу работать вообще.

Это по сути говорит, что если $1 не заполнен аргументом, вернемся к использованию STDIN - что я доволен концептуально.

Итак, вот мои вопросы:

  1. Я никогда не видел перенаправления (<) внутри подстановки команды процесса, без фактической команды, предшествующей ей (например, $(cat < somefile.ext)). Итак, что же на самом деле происходит (мелочность), когда подстановка команды процесса получает перенаправление без вызова другой команды?
  2. Почему вообще необходимо заключать перенаправление STDIN в подстановку команд процесса? (на самом деле, когда я пишу это, мне приходит в голову, я не проверял это без, но я буду держать это простым).
  3. Это безопасно? Я использовал его с многострочным STDIN, и он до сих пор не сломался. Где это может упасть (если где-нибудь?).

2 ответа

Решение
  1. $(..): из руководства bash - подстановка команд, а не подстановка процессов <(..), и из подстановки команд

Подстановка команд $(cat file) может быть заменена эквивалентной, но более быстрой $ (

  1. /dev/stdin символическая ссылка на /proc/self/fd/0удобно здесь из-за $(<..) синтаксис, который ожидает файл.

  2. это может вызвать проблемы, потому что команда может быть заблокирована, пока стандартный ввод не будет закрыт. это безопасно в том смысле, что многострочный ввод будет сохранен, потому что двойные кавычки.

Наконец, создание канала и разветвление процесса (как в mv -v foo.ext bar.ext | log) для каждой команды журнала может быть неэффективным.

Отвечая на ваши вопросы

  • Вы перепутали синтаксис между использованием процесса подстановки, который принимает синтаксис <(cmd) и простое перенаправление оболочки < file, В простой форме, < в основном это читать со стандартного ввода и > записать на стандартный вывод. Синтаксис < file это сокращенный синтаксис для размещения содержимого file сделан доступным на стандартном вводе, который может быть прочитан командами.
  • Поэтому, когда вы бежите cat < file, это в основном ставит содержание file в стандартном дескрипторе входного файла, который позже, чем read посредством cat процесс. Преимущество использования $(<file) будет оболочка не имеет форк внешнего процесса cat и просто использовать свой собственный механизм для чтения содержимого файла.
  • $(..) это синтаксис для подстановки команд, где команда запускается в среде под-оболочки и $(..) заменяется стандартным выводом команды. Для особого случая "$(<file)" т. е. без каких-либо команд и только задействованных перенаправлений оболочка вместо чтения со стандартного ввода начинает чтение с начала файла и помещает результат в стандартный вывод.
Другие вопросы по тегам