Механика этого синтаксиса оболочки: $ {1: - $ ( - PullRequest
0 голосов
/ 30 января 2019

Недавно я столкнулся с этим действительно аккуратным синтаксисом в контексте создания 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)).Итак, что же на самом деле происходит (мимолетно), когда подстановка команды process получает перенаправление без вызова другой команды?
  2. Почему необходимо обернуть перенаправление STDIN в процесс подстановка команд вообще?(на самом деле, когда я пишу это, мне приходит в голову, я не проверял это без, но я буду держать это простым).
  3. Это безопасно ?Я использовал его с многострочным STDIN, и он до сих пор не сломался.Где это может упасть (если где-нибудь?).

Ответы [ 2 ]

0 голосов
/ 30 января 2019

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

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

Подстановка команд $ (файл cat) может быть заменена эквивалентной, но более быстрой $ (<файл).</p>

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

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

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

...