Команда Cat и эхо

14

Я хотел бы объединить вывод из echo с содержимым файла. Я попробовал следующую команду:

echo "abc" | cat 1.txt > 2.txt

но 2.txtфайл содержит только содержимое из 1.txt. Почему это не работает?

Ringger81
источник
3
Такие программы, как catчтение только из стандартного ввода, если они не имеют аргументов имени файла.
Бармар

Ответы:

23

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

Вы можете использовать -в качестве псевдо-имени файла для обозначения стандартного ввода для cat. С man catустановки msys2:

EXAMPLES
       cat f - g
              Output f's contents, then standard input, then g's contents.

Так что постарайтесь

echo "abc" | cat - 1.txt > 2.txt

вместо.

MVW
источник
21

Как отмечали другие, ваша оригинальная команда не работает, потому что cat 1.txtигнорирует ее стандартный ввод. Либо укажите, что это должен быть его первый аргумент ( cat - 1.txt), либо используйте перенаправление блоков для перенаправления echo abc и cat 1.txt вместе. Для остроумия:

{ echo abc; cat 1.txt; } > 2.txt 

Соответствующая выдержка из руководства ( man bash):

Составные команды Составная
команда является одной из следующих. В большинстве случаев список в описании команды может быть отделен от остальной части команды одним или несколькими символами новой строки и может сопровождаться символом новой строки вместо точки с запятой.

(список)

    Список выполняется в среде оболочки (см. ниже КОМАНДА ИСПОЛНИТЕЛЬНОЙ СРЕДЫ). Переменные и встроенные команды, которые влияют на среду оболочки, не остаются в силе после ее завершения. Статус возврата - это статус выхода из списка.

{список; }

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

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

Nubarke
источник
7
( echo "abc"; cat 1.txt ) > 2.txt

Вы передали вывод эха в cat, но cat не использовал ввод и проигнорировал его. Теперь команды выполняются одна за другой, и их выходные данные группируются (круглые скобки) и направляются в 2.txt.

Джерард Х. Пилле
источник
1
Этот ответ можно улучшить, объяснив, как он работает и почему первоначальная попытка ОП не работает.
Боб
ОК, попробовал.
Джерард Х. Пилле
5
Здесь не требуется явно подоболочка, возможно, было бы лучше использовать групповую команду. Смотрите мой ответ для более подробной информации.
Нубарке
Ах, но я бы никогда не использовал bash.
Джерард Х. Пилле
1
@ GerardH.Pille: Хотя ответ Даниэля цитирует bash(1)его, он описывает поведение, которое должна поддерживать каждая POSIX-совместимая оболочка.
G-Man говорит: «Восстановите Монику»
2

Ваша команда cat 1.txtничего не делает с выводом echo "abc".

Вместо этого: (echo "abc"; cat 1.txt) > 2.txt запишет вывод обеих команд в 2.txt.

muclux
источник
Этот ответ можно улучшить, объяснив, как работает предложенная альтернатива.
Боб
1

В любой оболочке POSIX вы можете использовать подстановку команд для использования в cat fileкачестве входных данных для echo:

echo $(cat file1.txt) "This Too"

В Bash вы можете использовать подстановку процессов и использовать echo в качестве другого «файла» для cat, как в:

cat file1.txt <(echo This Too)

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

Как и в любом другом ответе, cat игнорирует стандартный ввод, если у него есть файл для просмотра. (Мне тоже нравятся ответы Даниэля и mvw, +1 за них)

Xen2050
источник
1
Этот ответ можно улучшить, объяснив, почему первоначальная попытка ОП не работает (и, следовательно, почему это необходимо).
Боб
1
<(command)Конструкция является продолжением Баша. Это не POSIX, поэтому вы не можете полагаться на него в сценариях, которые должны выполняться с /bin/sh.
Риальто поддерживает Монику
0

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

alias hg="history | grep"

Однако в этом случае функция будет более читабельной, поскольку вы объединяете несколько дискретных (2) входных потоков, а также несколько команд bash. У вас есть два аргумента, первый из которых является строкой, а другой - путем к файлу. В конце вы хотите, чтобы результат был записан в поток вывода stdout.

В командной строке CLI введите это:

# ecat()        
{
echo ${1}
cat ${2}
}

Ваша функция называется ecat, которая запоминается.

Теперь вы можете ссылаться как

ecat "abc" 1.txt

Чтобы добавить, просто укажите другое назначение вывода для stdout:

ecat "abc" 1.txt >> 2.txt

Оператор перенаправления добавления '>>' добавит вывод в конец указанного файла.

Если вам это нравится, добавьте файл ~ / .bashrc для повторного использования.

declare -f ecat >> ~/.bashrc

Это также означает, что вы можете украшать и т. Д. В рамках определения вашей функции.

Также хорошая идея защитить файлы от перезаписи, добавив это в ~ / .bashrc

set noclobber
FrDarryl
источник
2
Чтобы ваша функция работала правильно, вы должны использовать "$1"и "$2". В этом контексте фигурные скобки не приносят никакой пользы. См ${name}вовсе не означает , что вы думаете , что делает ... .
G-Man говорит: «Восстановите Монику»
1
Как noclobberпредложение реагирует на поставленный вопрос? (Я также очень не убежден, что это хороший совет - изменение глобального поведения имеет тенденцию нарушать сценарии / советы / практики, созданные с учетом значений по умолчанию).
Чарльз Даффи
0

Следующий код также будет работать:

echo abc >> 1.txt && cat 1.txt > 2.txt

Вывод echo abc будет добавлен в 1.txt с помощью >>. После этого && скажет ему выполнить следующий набор команд, который будет cat 1.txt, а затем выведет его в 2.txt . По сути, он добавляет вывод первой команды в 1.txt, а затем отправляет вывод 1.txt в 2.txt.

Если вы хотите, чтобы abc появлялся первым, вы можете использовать следующий код:

echo abc >> 2.txt && cat 1.txt >> 2.txt
Насир Райли
источник
1
Это будет (1) положить abcв нижней части 2.txt; вопрос хочет это наверху. (2)  изменения в 1.txtфайл; это неприемлемо.
G-Man говорит «Восстановить Монику»
Где это сказано? Ringger81 никогда не указывал, где в 2.txt он хотел, чтобы появился abc. Вы предполагаете вещи, о которых вопрос никогда не говорит.
Насир Райли
(1) Хорошо, вы подняли действительную точку на # 1. В то время как в вопросе упоминается «вывод из echo» перед «содержимым файла» в тексте, а затем помещается команда « echobefore» catв образце, я предполагаю, что он никогда точно и явно не говорит о том , что он хочет вывод из echo до содержимое входного файла. Просто кажется, что большинство людей интерпретируют это так. (2)  1.txtявляется входным файлом. Вопрос ничего не говорит о модификации 1.txt. Тот факт, что входные файлы не должны быть изменены, само собой разумеется.
G-Man говорит: «Восстановите Монику»
Я могу понять вашу мысль о том, чтобы не изменять файл импута. Мой второй код позволит достичь желаемого эффекта без этого.
Насир Райли
1
Открытие файла, добавление к нему, закрытие его , открытие его снова, добавление к нему снова ... почему вместо того, чтобы просто открыть его один раз и сохранить перенаправление на месте для обеих операций?
Чарльз Даффи