Перенаправить вывод всех команд в файл, а не только последний

11

Я хочу добавить заголовок в файл с помощью echo, а затем использовать команду для создания остальной части файла. Это означает, что я буду использовать две отдельные команды.

Как мне записать вывод обеих команд в файл с перенаправлением?

я пробовал

echo "header line" | cut -c 1-5 input_file > output_file

echo "header line"; cut -c 1-5 input_file > output_file

Это только перенаправляет вывод из команды вырезать.

Следующая команда работает, но кажется неуклюжей:

echo "header line" > output_file; cut -c 1-5 input_file >> output_file

Каков умный способ решения моей проблемы?

Несчастный кот
источник

Ответы:

11

Проблема здесь не в перенаправлении Linux; скорее это фундаментальное недопонимание того, как работает трубопровод. Перенаправление здесь не работает, потому что на самом деле только обрезка печатает на стандартный вывод. stdout для команды echo был передан для вырезания stdin (который в этом случае не используется, так как указан файл).

echo "header line" > output_file && cut -c 1-5 input_file >> output_file

это то, что вы хотите, а не совсем не элегантно (я заменил вашу ;на &&так, чтобы команда cut выполнялась только в случае успешной записи заголовка; таким образом, она не будет выполняться, если у вас нет прав на создание или запись в output_file ).

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

(echo "header line"; cut -c 1-5 input_file) > output_file

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

Если вы хотите, чтобы cut передавал стандартный ввод в стандартный вывод, вы можете попробовать:

echo "header line" | cut -c 1-5 - input_file

(Тире это общий ярлык для стандартного ввода)

Тем не менее, это также будет выполнять операцию вырезания на stdin (в результате чего строка заголовка "header"). Трудно сказать, если это то, что вы хотите или нет из вопроса.

Сэм Уитед
источник
13

То, что вы ищете, это:

{ echo "header line"; cut -c 1-5 input_file; } > output_file
  • Этот синтаксис не имеет побочных эффектов, так как команды выполняются в текущей оболочке, а не в подоболочке
  • Существует четкое разграничение команд, которые идут в файл output_file
  • Он хорошо масштабируется, так что вы можете переписать его так:

{
  echo "header line"
  cut -c 1-5 input_file
  ... # insert new commands here
} > output_file

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

} > output_file 2>&1

Спасибо Оливье Дюлаку за напоминание об этом.

Если вы хотите, чтобы какой-то вывод внутри блока перешел на ваш экран, вы можете использовать этот синтаксис:

{
  echo "header line"
  echo "this line doesn't go to output_file" > /dev/tty
  cut -c 1-5 input_file
} > output_file
jlliagre
источник
+1: он более понятен и четко определяет, куда перенаправляется. Для того, чтобы перенаправить все ( в том числе сообщения об ошибке): { .... } > some_file 2>&1(будет «тряпки» some_file не тряпки, но запись в него вместо этого, просто изменить. >В >>: { ... } >> some_file 2>&1)
Оливье Дюлаком
4

Просто чтобы округлить ответы есть exec.

exec > output_file
echo "header line"
cut -c 1-5 input_file
hildred
источник
+1: в сценариях очень часто это используется (реже в командной строке, так как все начинает сбиваться с толку ^^)
Оливье Дюлак
Может ли кто-нибудь уточнить это решение? Я могу видеть, что он делает, но я не понимаю «exec» в этом контексте. Кроме того, это похоже на то, что вы должны снова отключить, если остальная часть вашего скрипта нуждается в обычном stdout.
Джо
1
когда вы используете exec в сценарии без команды, вы можете выполнить перенаправление ввода / вывода для exec, которое влияет на текущую оболочку и всех будущих потомков.
Hildred
Благодарю. Я не видел этого раньше. Я думаю, что это будет очень полезно.
Джо