Redirige la sortie de toutes les commandes vers le fichier, pas seulement la dernière

11

Je veux ajouter un en-tête à un fichier avec écho, puis utiliser une commande pour créer le reste du fichier. Cela signifie que j'utiliserai deux commandes distinctes.

Comment écrire la sortie des deux commandes dans un fichier avec redirection?

J'ai essayé

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

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

Cela redirige uniquement la sortie de la commande cut.

La commande suivante fonctionne, mais semble maladroite:

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

Quelle est la manière intelligente de résoudre mon problème?

Le chat unfun
la source

Réponses:

11

Le problème ici n'est pas un problème avec la redirection Linux; il s'agit plutôt d'une incompréhension fondamentale du fonctionnement du pipeline. Ici, la redirection ne fonctionne pas car seule la découpe s'imprime réellement sur la sortie standard. stdout pour la commande echo a été canalisé vers stdin de cut (qui n'est pas utilisé dans ce cas car un fichier est spécifié).

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

est ce que vous voulez, et pas du tout inélégant (j'ai remplacé votre ;par &&pour que la commande cut ne s'exécute que si l'en-tête est correctement écrit; de cette façon, il ne s'exécutera pas si vous n'avez pas les autorisations pour créer ou écrire dans le fichier de sortie ).

Vous pouvez également tout faire en sous-shell, par exemple.

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

mais cela ne présente aucun avantage réel et avec des exemples plus complexes, cela peut entraîner des problèmes si vous n'êtes pas familier avec la portée du sous-shell.

Si vous voulez couper pour passer stdin à stdout, vous pouvez essayer:

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

(Le tiret est un raccourci commun pour stdin)

Cependant, cela effectuera également l'opération de coupure sur stdin (résultant en une ligne d'en-tête "en-tête"). Il est difficile de dire si c'est ce que vous voulez ou non à la question.

Sam Whited
la source
13

Ce que vous recherchez est:

{ echo "header line"; cut -c 1-5 input_file; } > output_file
  • Cette syntaxe n'a pas d'effets secondaires car les commandes sont exécutées dans le shell actuel, pas un sous-shell
  • Il y a une délimitation claire des commandes qui vont au fichier de sortie
  • Il évolue bien car vous pouvez le réécrire de cette façon:

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

Si vous souhaitez que la sortie d'erreur aille dans le même fichier, vous pouvez modifier la dernière ligne de cette façon:

} > output_file 2>&1

Merci à Olivier Dulac d'avoir rappelé cette astuce.

Si vous souhaitez qu'une sortie à l'intérieur du bloc passe à votre écran, vous pouvez utiliser cette syntaxe:

{
  echo "header line"
  echo "this line doesn't go to output_file" > /dev/tty
  cut -c 1-5 input_file
} > output_file
jlliagre
la source
+1: c'est plus clair et identifie clairement ce qui est redirigé où. Pour rediriger tout (y compris msg d'erreur): { .... } > some_file 2>&1(sera « clobber » un_fichier à ne pas clobber, mais au lieu d'y ajouter du , il suffit de changer le. >En >>: { ... } >> some_file 2>&1)
Olivier Dulac
4

Pour compléter les réponses, il y a exec.

exec > output_file
echo "header line"
cut -c 1-5 input_file
hildred
la source
+1: dans les scripts, il est très courant de l'utiliser (moins sur la ligne de commande, car les choses commencent à devenir déroutantes ^^)
Olivier Dulac
Quelqu'un pourrait-il élaborer sur cette solution? Je peux voir ce qu'il fait, mais je ne comprends pas «exec» dans ce contexte. En outre, cela ressemble à quelque chose que vous devez désactiver à nouveau si le reste de votre script nécessite une sortie standard.
Joe
1
lorsque vous utilisez exec dans un script sans commande, vous pouvez effectuer une redirection d'E / S sur l'exec qui affecte le shell actuel et tous les futurs enfants.
hildred
Merci. Je n'ai jamais vu ça auparavant. Je pense que ce sera très utile.
Joe