Как вы используете перенаправление вывода в сочетании с here-документами и cat?

56

Допустим, у меня есть сценарий, который я хочу передать по конвейеру другой команде или перенаправить в файл ( shдля примера приведен конвейер ). Предположим, что я использую Bash.

Я мог бы сделать это используя echo:

echo "touch somefile
echo foo > somefile" | sh

Я также мог бы сделать почти то же самое, используя cat:

cat << EOF
touch somefile
echo foo > somefile
EOF

Но если я заменю «EOF» на «EOF | sh», он просто подумает, что это часть heredoc.

Как я могу сделать так, чтобы catвыводить текст из стандартного ввода, а затем направить его в произвольное место?

strugee
источник
touchразве там, что именно вы хотите? просто прочитать входной файл и перенаправить на другой с помощью stdout?
Рахул Патил
2
@RahulPatil, конечно, это бесполезно. Я просто хотел пример с более чем одной строкой, чтобы лучше проиллюстрировать наследственность. И посмотрите на пример с использованием echo- мне было интересно, что будет использовать эквивалент этого cat.
Струджи
Ваш пример - создание shсценария из нескольких строк и передача его напрямую sh. Я обнаружил, что ваш Q ищет передачу текстового вывода нескольких команд, включая документ HERE, непосредственно в команду. Вот что делает ответ Эша во втором примере.
Дэйв Икс

Ответы:

91

Есть несколько способов сделать это. Самое простое, вероятно, это:

cat <<EOF | sh
touch somefile
echo foo > somefile
EOF

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

(
cat <<EOF
touch somefile
echo foo > somefile
EOF
) | sh

Это работает также, но без вложенной оболочки:

{
cat <<EOF
touch somefile
echo foo > somefile
EOF
} | sh

Больше вариаций:

cat <<EOF |
touch somefile
echo foo > somefile
EOF
  sh

Или же:

{ cat | sh; } << EOF
touch somefile
echo foo > somefile
EOF

Кстати, я ожидаю, что использование catв вашем вопросе является заполнителем для чего-то еще. Если нет, возьмите это, как это:

sh <<EOF
touch somefile
echo foo > somefile
EOF

Что можно упростить до этого:

sh -c 'touch somefile; echo foo > somefile'

или же:

sh -c 'touch somefile
echo foo > somefile'

Перенаправление вывода вместо трубопровода

sh >out <<EOF
touch somefile
echo foo > somefile
EOF

Использование, catчтобы получить эквивалент echo test > out:

cat >out <<EOF
test
EOF

Несколько Здесь Документов

( cat; echo ---; cat <&3 ) <<EOF 3<<EOF2
hi
EOF
there
EOF2

Это производит вывод:

hi
---
there

Вот что происходит:

  • Оболочка видит ( ... )и запускает вложенные команды в подоболочке.
  • Кот и эхо достаточно просты. cat <&3Говорит , чтобы запустить кошку с дескриптором файла (FD) 0 (STDIN) , переадресованные с дескриптором 3; Другими словами, отследите ввод от fd 3.
  • Перед (...)запуском оболочка видит два перенаправленных здесь документа и заменяет fd 0 ( <<EOF) и fd 3 ( 3<<EOF2) на стороне чтения каналов
  • Как только начальная команда запущена, оболочка читает свой стандартный ввод до достижения EOF и отправляет его на сторону записи первого канала
  • Затем он делает то же самое с EOF2 и стороной записи второго канала.
ясень
источник
учитывая второй пример, можете ли вы привести пример с перенаправлением stdout вместо конвейера?
Струджи
Я отредактировал ответ с примером перенаправления; это форма, которую вы хотели отредактировать? Если нет, можете ли вы дать первую строку этой части, чтобы уточнить?
ясень
1
Это может помочь понять, как оболочка обрабатывает это. Когда он оценивает командную строку и находит << EOF, он читает из стандартного ввода до тех пор, пока не будет найдена либо строка, содержащая только EOF, либо конец ввода. Все остальное в исходной командной строке, которое еще не было обработано, продолжает обрабатываться. Так, например, можно сделать что-то вроде этого: (cat; echo ---; exec <&3; cat) <<EOF 3<<EOF2 >outи затем ввести эту команду, используя два блока здесь подряд.
ясень
Ваше объяснение обработки оболочки было интересным, но у меня над головой :) Что я хотел знать, так это то, что было бы catэквивалентно echo test > outиспользованию heredoc. Принимая во внимание, что ваш данный пример добавил перенаправление в конце канала.
Струджи
1
@OlivierDulac - я добавил пример множественного heredoc в ответ.
пепел
1

Я просто хочу отметить, что использование meowтак же, как и EOF.

Этот скрипт будет добавлять Meow!в файл с именем cat:

#!/bin/sh
cat <<meow>> cat
Meow!
meow

Сохраните как catsи сделайте его исполняемым chmod +x cats, затем запустите его ./cats:

$ ./cats
$ cat cat
Meow!
$ ./cats
$ cat cat
Meow!
Meow!

Объяснение:

  • cat <<meowявляется здесь документ синтаксис. Он инструктирует сценарий подобрать блок текста, который следует за этой строкой, пока не встретит строку meow. Затем содержимое будет выводиться (или передаваться по каналу).
  • >> catтрубы в файл с именем cat.
  • Использование >вместо >>будет перезаписывать файл вместо добавления к нему.
  • Meow!это содержимое документа здесь .
  • meowявляется конечным маркером для документа здесь . Содержание, с использованием >>, добавлено cat.

Трубопровод как в стандартный вывод, так и в файл:

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

catне может как выводить текст, так и передавать текст, но teeидеально подходит для того, что вы просите:

echo echo | tee tee

Это будет выводить строку echoи записывать echoв файл с именем tee.

Вы также можете передать вывод cat, если это является частью требования, либо с помощью:

echo echo | tee tee | cat </dev/stdin

Или просто:

echo echo | tee tee | cat

Содержание файла:

$ cat tee
echo
Александр
источник
1
Это на самом деле не отвечает на вопрос. Также >не создает трубы, как подразумевает ваша последняя пуля.
стружка
2
@strugee, >может создавать каналы в том zshслучае, когда один и тот же fd перенаправляется несколько раз, как в echo foo >&1 > teeили echo foo > tee | cat, где zshреализует внутреннее, teeчтобы передать выходные данные echoобоим catи teeфайлу.
Стефан Шазелас
Обновил мой ответ, чтобы лучше ответить на вопрос.
Александр