Почему в выводе «echo 123> (cat)» есть «/ dev / fd / 63»?

Возможно, вы знаете, что sync полезен при копировании некоторых больших данных на медленный диск. Просто чтобы убедиться, что на внешний диск все записано, прежде чем его вытаскивать!

5
31.07.2018, 08:28
4 ответа

Для полноты

cmd1 >(cmd2)

в основном совпадает с

cmd1 | cmd2

в оболочке яш, и только в этой оболочке.

В этой оболочке >(cmd) — это перенаправление процесса, в отличие от >(cmd) из ksh/bash/zsh, который является процессом замены.

Это не совсем эквивалентно, потому что в cmd1 >(cmd2), yash не ожидает cmd2, так что вы можете обнаружить, что:

$ yash -c 'echo A >(cat); echo B'
B
A
$ yash -c 'echo A | cat; echo B'
A
B

Напротив, процесс substitution расширяется до пути к файлу (обычно это именованный канал или /dev/fd/, где — это fd в заранее созданный канал), который при открытии для записи позволит отправлять вывод в cmd.

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

ksh -c 'cmd1 > >(cmd2)'

для эмуляции yash перенаправление процесса не будет работать. Там вы должны передать это имя файла, полученное в результате замены, в качестве аргумента команде, например:

ksh -c 'diff <(echo a) <(echo b)'

Это будет работать в bash и zsh.

Однако в bash, как и в случае перенаправления процесса yash, оболочка не ожидает команды (cmd2). Итак:

$ bash -c 'echo A > >(cat); echo B'
B
A

ksh замену процесса можно эмулировать с помощью yash с помощью:

cmd1 /dev/fd/5 5>(cmd2)   

Например:

diff /dev/fd/3 3<(echo a) /dev/fd/4 4<(echo b)
6
27.01.2020, 20:31

Поскольку это то, что делает подстановка процесса , команда внутри подстановки выглядит как имя файла. Внутри он соединяет команды через канал, предоставляя путь /dev/fd/NNк основной команде, поэтому он может открыть уже открытый файловый дескриптор -в канале.

Это не то же самое, что трубка.Каналы соединяют stdoutс stdinбез участия чего-либо похожего на имена файлов. Замена процесса более гибкая, поскольку вы можете иметь несколько таких замен в одной командной строке, но для этого требуется, чтобы основная команда открывала файлы по имени (, например. cat, а неecho).

Вы можете эмулировать конвейер с заменой процесса, выполнив что-то вроде этого:

echo foo > >(cat -n)
5
27.01.2020, 20:31
$ echo 1 >(cat > /dev/null)
1 /dev/fd/63
$ echo echo >(cat /dev/null)
echo /dev/fd/63

# We can trace how the commands are executed
# so long as we avoid using shell builtin commands,
# and run the equivalent external program instead, i.e. /usr/bin/echo

$ strace -f -e execve bash -c '/usr/bin/echo >(cat /dev/null)'
execve("/usr/bin/bash", ["bash", "-c", "/usr/bin/echo >(cat /dev/null)"], [/* 56 vars */]) = 0
strace: Process 4213 attached
[pid  4212] execve("/usr/bin/echo", ["/usr/bin/echo", "/dev/fd/63"], [/* 56 vars */]) = 0
strace: Process 4214 attached
[pid  4214] execve("/usr/bin/cat", ["cat", "/dev/null"], [/* 56 vars */]/dev/fd/63
) = 0
[pid  4212] +++ exited with 0 +++
[pid  4214] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=4214, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

# Apparently, the order of evaluation is arranged so this works nicely:

$ echo 1 > >(cat > /dev/null)
$
3
27.01.2020, 20:31

Замена процесса >(thing)будет заменена именем файла. Это имя файла соответствует файлу, который подключен к стандартному входу thingвнутри подстановки.

Следующий пример будет лучшим примером его использования:

$ sort -o >(cat -n >/tmp/out) ~/.profile

Это отсортирует файл ~/.profileи отправит вывод в cat -n, который пронумерует строки и сохранит результат в /tmp/out.

Итак, чтобы ответить на ваш вопрос :Вы получаете этот вывод, потому что echoполучает два аргумента 123и /dev/fd/63. /dev/fd/63— это файл, подключенный к стандартному входу процесса catв замене процесса.

Немного изменив код вашего примера:

$ echo 101 > >(cat)

Это выведет только 101на стандартный вывод (вывод echoбудет перенаправлен в файл, который служит входом для cat, а catвыдаст содержимое этого файла на стандартный вывод ).


Также обратите внимание, что в конвейере cmd1 | cmd2cmd2может вообще не работать в той же оболочке, что и cmd1(, в зависимости от используемой вами реализации оболочки ). ksh93работает так, как вы описываете (ту же оболочку ), в то время как bashсоздает подоболочку для cmd2(, если не установлен параметр оболочки lastpipeи управление заданиями не активно ).

11
27.01.2020, 20:31

Теги

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