В чем разница между <<, <<<и < <в Баш?
В чем разница между <<, <<<и < <в Баш?
Ответы:
Здесь документ
<<известен как here-documentструктура. Вы даете программе знать, каким будет конечный текст, и всякий раз, когда этот разделитель виден, программа считывает все данные, которые вы дали программе, в качестве входных данных и выполняет над ним задачу.
Вот что я имею в виду:
$ wc << EOF
> one two three
> four five
> EOF
2 5 24
В этом примере мы говорим wcпрограмме дождаться EOFстроки, затем введите пять слов, а затем введите, EOFчтобы сообщить, что мы закончили ввод данных. По сути, это похоже на самодельный запуск wc, набрав слова, затем нажавCtrlD
В bash они реализуются через временные файлы, обычно в форме /tmp/sh-thd.<random string>, тогда как в dash они реализуются как анонимные каналы. Это можно наблюдать с помощью отслеживания системных вызовов с помощью straceкоманды. Замените bashна, shчтобы увидеть, как /bin/shвыполняется это перенаправление.
$ strace -e open,dup2,pipe,write -f bash -c 'cat <<EOF
> test
> EOF'
Здесь строка
<<<известен как here-string. Вместо того, чтобы вводить текст, вы даете предварительно подготовленную строку текста программе. Например, с такой программой, которую bcмы можем сделать, bc <<< 5*4чтобы просто получить вывод для этого конкретного случая, нет необходимости запускать bc в интерактивном режиме.
Здесь строки в bash реализуются через временные файлы, как правило, в формате /tmp/sh-thd.<random string>, который впоследствии не связывается, что делает их временно занимающими некоторое пространство памяти, но не отображаются в списке /tmpзаписей каталога, и фактически существуют как анонимные файлы, которые все еще могут на него можно ссылаться через дескриптор файла самой оболочкой, и этот дескриптор файла наследуется командой и впоследствии дублируется на дескриптор файла 0 (stdin) через dup2()функцию. Это можно наблюдать через
$ ls -l /proc/self/fd/ <<< "TEST"
total 0
lr-x------ 1 user1 user1 64 Aug 20 13:43 0 -> /tmp/sh-thd.761Lj9 (deleted)
lrwx------ 1 user1 user1 64 Aug 20 13:43 1 -> /dev/pts/4
lrwx------ 1 user1 user1 64 Aug 20 13:43 2 -> /dev/pts/4
lr-x------ 1 user1 user1 64 Aug 20 13:43 3 -> /proc/10068/fd
И через трассировку системных вызовов (вывод сокращен для удобства чтения; обратите внимание, как временный файл открывается как fd 3, данные записываются в него, затем он снова открывается с O_RDONLYфлагом как fd 4 и позже не связывается, затем dup2()на fd 0, который наследуется catпозднее ):
$ strace -f -e open,read,write,dup2,unlink,execve bash -c 'cat <<< "TEST"'
execve("/bin/bash", ["bash", "-c", "cat <<< \"TEST\""], [/* 47 vars */]) = 0
...
strace: Process 10229 attached
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
[pid 10229] write(3, "TEST", 4) = 4
[pid 10229] write(3, "\n", 1) = 1
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDONLY) = 4
[pid 10229] unlink("/tmp/sh-thd.uhpSrD") = 0
[pid 10229] dup2(4, 0) = 0
[pid 10229] execve("/bin/cat", ["cat"], [/* 47 vars */]) = 0
...
[pid 10229] read(0, "TEST\n", 131072) = 5
[pid 10229] write(1, "TEST\n", 5TEST
) = 5
[pid 10229] read(0, "", 131072) = 0
[pid 10229] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=10229, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++
Мнение: возможно, потому что здесь строки используют временные текстовые файлы, это является возможной причиной, по которой здесь-строки всегда вставляют завершающий символ новой строки, так как текстовый файл по определению POSIX должен иметь строки, заканчивающиеся символом новой строки.
Процесс замены
Как объясняет tldp.org ,
Подстановка процессов направляет выходные данные процесса (или процессов) в стандартный поток ввода другого процесса.
Таким образом, в действительности это похоже на передачу стандартного вывода одной команды другой, например echo foobar barfoo | wc. Но обратите внимание: на странице руководства bash вы увидите, что она обозначена как <(list). Таким образом, вы можете перенаправить вывод нескольких (!) Команд.
Примечание: технически, когда вы говорите, что < <вы имеете в виду не одну вещь, а два перенаправления с одним <и перенаправление процесса из вывода <( . . .).
Что произойдет, если мы просто заменим процесс?
$ echo <(echo bar)
/dev/fd/63
Как видите, оболочка создает временный файловый дескриптор, /dev/fd/63куда направляется вывод (который, согласно ответу Жиля , является анонимным каналом). Это означает, <что перенаправляет этот дескриптор файла в качестве ввода в команду.
Очень простой пример - сделать подстановку процесса из двух команд echo в wc:
$ wc < <(echo bar;echo foo)
2 2 8
Таким образом , здесь мы делаем оболочки создать дескриптор файла для всех вывод , что происходит в круглых скобках и перенаправлять , что в качестве вклада в wc.Как ожидается, туалет получает тот поток из двух эхо - команд, что само по себе будет выводить две линии, каждая из которых имеет слово, и соответственно у нас есть 2 слова, 2 строки и 6 символов плюс две новые строки.
Дополнительное примечание: Подстановка процесса может упоминаться как bashism (команда или структура, используемая в расширенных оболочках, например bash, но не указанная в POSIX), но она была реализована kshдо существования bash как страница руководства ksh, и этот ответ предполагает. Снаряды любят tcshи mkshне имеют процесса замены. Итак, как мы могли бы перенаправить вывод нескольких команд в другую команду без подстановки процесса? Группировка плюс обвязка!
$ (echo foo;echo bar) | wc
2 2 8
По сути, это то же самое, что и в предыдущем примере. Однако это не так, как замена процесса, поскольку мы делаем стандартный вывод всей подоболочки и стандартный wc связью с каналом . С другой стороны, подстановка процесса заставляет команду прочитать временный дескриптор файла.
Так что, если мы можем сделать группировку с трубопроводом, зачем нам нужна замена процесса? Потому что иногда мы не можем использовать трубопровод. Рассмотрим приведенный ниже пример - сравнение выходных данных двух команд с diff(которым нужны два файла, и в этом случае мы даем ему два файловых дескриптора)
diff <(ls /bin) <(ls /usr/bin)
< <используется, когда кто-то получает стандартный вывод из процесса подстановки . Такая команда может выглядеть следующим образом : cmd1 < <(cmd2). Например,wc < <(date)
< < Само по себе не вещь , в случае замены процесса это просто <сопровождается чем-то еще, что начинается с<
<<<сначала был реализован порт Unix оболочки Plan 9 rc, а затем принят zsh, bash и ksh93. Я бы тогда не назвал это башизмом.
echo 'foo' | read; echo ${REPLY}будет не возвращаться foo, потому что readначинается в суб-оболочки - трубопровод начинает подоболочку. Тем не менее, read < <(echo 'foo'); echo ${REPLY}правильно возвращается foo, потому что нет вложенной оболочки.
< < это синтаксическая ошибка:
$ cat < <
bash: syntax error near unexpected token `<'
< <()Является ли процесс замены ( <()) в сочетании с перенаправлением ( <):
Придуманный пример:
$ wc -l < <(grep ntfs /etc/fstab)
4
$ wc -l <(grep ntfs /etc/fstab)
4 /dev/fd/63
При замене процесса путь к дескриптору файла используется как имя файла. Если вы не хотите (или не можете) использовать имя файла напрямую, вы объединяете подстановку процесса с перенаправлением.
Чтобы было ясно, нет < <оператора.
<()дает имя, похожее на имя файла, поэтому оно более полезно - < <()заменяет стандартный ввод, когда это может не понадобиться. В wcпоследнем случае оказывается более полезным. Это может быть менее полезным в других местах
< <это синтаксическая ошибка, вы, вероятно, имеете в виду, command1 < <( command2 )что это простое перенаправление ввода с последующей подстановкой процесса и очень похоже, но не эквивалентно:
command2 | command1
Разница в том, что вы работаете, bashзаключается command1в том, что во втором случае он запускается в подоболочке, а в первом - в текущей оболочке. Это означает, что переменные, установленные в command1, не будут потеряны с вариантом замены процесса.
< <выдаст синтаксическую ошибку. Правильное использование заключается в следующем:
Объясняя с помощью примеров:
Пример для < <():
while read line;do
echo $line
done< <(ls)
В приведенном выше примере вход в цикл while будет поступать из lsкоманды, которую можно читать построчно и echoредактировать в цикле.
<()используется для замены процесса. Дополнительную информацию и пример <()можно найти по этой ссылке: