Понимание замены команды чтения файла Bash

Не виджет как таковой, но можно получить сочетания клавиш путем добавления

awful.key({}, "XF86AudioPlay", function () awful.util.spawn_with_shell("nyxmms2 toggle") end),
awful.key({}, "XF86AudioStop", function () awful.util.spawn_with_shell("nyxmms2 stop") end),
awful.key({}, "XF86AudioPrev", function () awful.util.spawn_with_shell("nyxmms2 prev") end),
awful.key({}, "XF86AudioNext", function () awful.util.spawn_with_shell("nyxmms2 next") end)

к Вашему rc.lua файл.

Кроме того, виджет официального сайта был обновлен, и код там теперь хорошо работает для меня.

11
03.09.2017, 08:43
5 ответов

< не непосредственно аспект замены команды Bash . Это оператор перенаправления (например, труба), которые некоторые оболочки позволяют без команды (POSIX не указывает это поведение).

Возможно, было бы более понятно с большим количеством пробелов:

echo $( < $FILE )

Это эффективно * так же, как и более безопасный POSIX

echo $( cat $FILE )

... что также эффективно *

echo $( cat < $FILE )

давайте начнем с этой последней версией. Это работает CAT без аргументов, что означает, что он будет читаться с стандартного ввода. $ Файл перенаправляется на стандартный вход из-за <, поэтому CAT ставит его содержимое в стандартном выходе. $ (команда) ПОДПИСАНИЕ ПОМОЩЬ Потоптация CAT вывод в аргументы для ECHO .

В Bash (но не в стандарте POSIX) вы можете использовать < без команды. Bash ZSH ZSH и ksh , но не DASH ) будет интерпретировать, что как будто Cat <, хотя без вызывая новый подпроцесс. Поскольку это родом для оболочки, это быстрее, чем буквально запустить внешнюю команду CAT . * Вот почему я говорю «эффективно такой же, как».

-3
27.01.2020, 19:58

Думайте о замене команды как о выполнении команды, как обычно, и сбросе вывода в месте выполнения команды.

Вывод команд можно использовать в качестве аргументов к другой команде, чтобы устанавливает переменную, и даже для генерации списка аргументов в формате a for Петля.

foo=$(echo "bar") установит значение переменной $foo в bar; вывод команды echo bar.

Замена команды

-1
27.01.2020, 19:58

Поскольку Bash Bash . Это внутри необходима для вас, расширило имя файла и кошек файл на стандартную вывод, как если бы вы делали $ (CAT . Это функция Bash, может быть, вам нужно посмотреть в исходный код , чтобы точно знать, как он работает.

Здесь функция для обработки этой функции (из Bash исходный код, файл Встроенные / EvalString.C ):

/* Handle a $( < file ) command substitution.  This expands the filename,
   returning errors as appropriate, then just cats the file to the standard
   output. */
static int
cat_file (r)
     REDIRECT *r;
{
  char *fn;
  int fd, rval;

  if (r->instruction != r_input_direction)
    return -1;

  /* Get the filename. */
  if (posixly_correct && !interactive_shell)
    disallow_filename_globbing++;
  fn = redirection_expand (r->redirectee.filename);
  if (posixly_correct && !interactive_shell)
    disallow_filename_globbing--;

  if (fn == 0)
    {
      redirection_error (r, AMBIGUOUS_REDIRECT);
      return -1;
    }

  fd = open(fn, O_RDONLY);
  if (fd < 0)
    {
      file_error (fn);
      free (fn);
      return -1;
    }

  rval = zcatfd (fd, 1, fn);

  free (fn);
  close (fd);

  return (rval);
}

Обратите внимание, что $ (<имя файла ) не совсем эквивалентно $ (имя файла CAT) ; Последнее потерпит неудачу, если имя файла запускается с тире - .

$ (<имя файла) изначально было из ksh и добавляли в Bash из Bash-2.02 .

8
27.01.2020, 19:58

$(<file)(также работает с`<file`)— это специальный оператор оболочки Корна, скопированный zshи bash. Это очень похоже на подстановку команд, но на самом деле это не так.

В оболочках POSIX простая команда:

< file var1=value1 > file2 cmd 2> file3 args 3> file4

Все части являются необязательными, у вас могут быть только перенаправления, только команды, только назначения или комбинации.

Если есть перенаправления, но нет команды, перенаправления выполняются (, поэтому > fileоткрывается и усекается file), но тогда ничего не происходит. Так

< file

Открывает fileдля чтения, но дальше ничего не происходит, так как нет команды. Итак, fileзакрывается и все. Если бы $(< file)была простой подстановкой команды , то она не расширилась бы до нуля.

В спецификации POSIX , в $(script), если scriptсостоит только из перенаправлений, то приводит к неопределенным результатам . Это сделано для того, чтобы обеспечить особое поведение оболочки Korn.

В ksh (здесь протестировано с ksh93u+), если скрипт состоит из одной и только одной простой команды(хотя до и после разрешены комментарии до и после ), которые состоят только из перенаправлений (нет команды, нет назначения )и если первое перенаправление является стандартным вводом (fd 0 )только ввод (<, <<или<<<)перенаправление,так:

  • $(< file)
  • $(0< file)
  • $(<&3)(также $(0>&3)на самом деле, поскольку это один и тот же оператор)
  • $(< file > foo 2> $(whatever))

, но не:

  • $(> foo < file)
  • или$(0<> file)
  • или$(< file; sleep 1)
  • или$(< file; < file2)

, затем

  • все перенаправления, кроме первого, игнорируются (они анализируются)
  • и расширяется до содержимого файла/heredoc/herestring (или того, что можно прочитать из дескриптора файла при использовании таких вещей, как<&3)минус завершающие символы новой строки.

как при использовании $(cat < file), за исключением того, что

  • чтение выполняется внутри оболочки, а неcat
  • не используется ни труба, ни дополнительный процесс
  • как следствие вышеизложенного, поскольку код внутри не запускается в подоболочке, любые модификации остаются после этого (как в $(<${file=foo.txt})или$(<file$((++n))))
  • ошибки чтения (, хотя и не ошибки при открытии файлов или дублировании файловых дескрипторов ), молча игнорируются.

В zshто же самое, за исключением того, что это особое поведение запускается только при наличии только одного перенаправления ввода файла(<fileили 0< file, нет <&3, <<<here, < a < b...)

Однако, за исключением случаев эмуляции других оболочек, в:

< file
<&3
<<< here...

то есть, когда есть только перенаправления ввода без команд, вне подстановки команд, zshзапускает$READNULLCMD(пейджер по умолчанию ), а когда есть перенаправления ввода и вывода,$NULLCMD(catпо умолчанию ), поэтому, даже если $(<&3)не распознан как этот специальный оператор, он все равно будет работать, как в ksh, хотя при вызове пейджера для этого (этот пейджер действует как cat, поскольку его стандартный вывод будет быть трубой ).

Однако в то время как ksh$(< a < b)расширяется до содержимого a, в zshоно расширяется до содержимого aиb(или просто b, если multiosопция отключена ),$(< a > b)скопирует aв bи ничего не расширит и т. д.

bashимеет аналогичный оператор, но с некоторыми отличиями:

  • комментарии разрешены до, но не после:

      echo "$(
         # getting the content of file
         < file)"
    

работает, но:

    echo "$(< file
       # getting the content of file
    )"

расширяется до нуля.

  • как и в zsh, только одно перенаправление файла stdin, хотя возврата к $READNULLCMDнет, поэтому $(<&3), $(< a < b)выполняют перенаправления, но не расширяются.
  • по какой-то причине, хотя bashне вызывает cat, он все же разветвляет процесс, который передает содержимое файла через канал, что делает его гораздо менее оптимизированным, чем в других оболочках. По сути, это похоже на $(cat < file), где catбудет встроенным cat.
  • как следствие вышеизложенного, любые изменения, сделанные внутри, впоследствии теряются (в $(<${file=foo.txt}), упомянутом выше, например, что $fileназначение теряется впоследствии ).

В bashIFS= read -rd '' var < file(также работает вzsh)— это более эффективный способ чтения содержимого текстового файла в переменную. Это также имеет преимущество сохранения завершающих символов новой строки. См. также $mapfile[file]вzsh(в модуле zsh/mapfileи только для обычных файлов ), который также работает с двоичными файлами.

Обратите внимание, что варианты kshна основе pdksh -имеют несколько вариаций по сравнению с ksh93. Интересно, что вmksh(одна из тех оболочек, производных от pdksh -), в

var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)

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

Для переноса на все версии ksh, zshи bash,лучше всего ограничиться только тем, $(<file)избегая комментариев и помня о том, что модификации переменных, сделанные внутри, могут сохраняться, а могут и не сохраняться.

20
20.08.2021, 12:36

Вот фрагмент кода bash 3.2, показывающий разницу с объяснением:

  • Используйте strace для отслеживания процессов и отображения вызовов execvestrace -f -e trace=execve
  • Запуск команд чтения bash из строкиbash -c-с параметром/bin/cat
  • и без него.
  • Разделите выходные данные в режиме рядом друг с другом на 80 столбцов, чтобы они уместились здесьdiff -y -W 80

Вы можете увидеть дополнительный execve(/bin/cat...)на правой стороне дифференциала:

$ echo $BASH_VERSION
3.2.25(1)-release
$ echo "hi" >/tmp/f
$ strace -f -e trace=execve /bin/bash -c 'echo $(</tmp/f)'          >/tmp/no_cat 2>&1
$ strace -f -e trace=execve /bin/bash -c 'echo $(/bin/cat </tmp/f)' >/tmp/wi_cat 2>&1
$ diff -y -W 80 /tmp/no_cat /tmp/wi_cat
execve("/bin/bash", ["/bin/bash", "-c | execve("/bin/bash", ["/bin/bash", "-c
Process 24253 attached (waiting for p | Process 24256 attached (waiting for p
Process 24253 resumed (parent 24252 r | Process 24256 resumed (parent 24255 r
Process 24253 detached                | Process 24257 attached (waiting for p
                                      > Process 24257 resumed (parent 24256 r
                                      > Process 24256 suspended
                                      > [pid 24257] execve("/bin/cat", ["/bin
                                      > Process 24256 resumed
                                      > Process 24257 detached
                                      > [pid 24256] --- SIGCHLD (Child exited
                                      > Process 24256 detached
--- SIGCHLD (Child exited) @ 0 (0) --   --- SIGCHLD (Child exited) @ 0 (0) --
hi                                      hi
0
15.09.2021, 21:52

Теги

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