Commande et écho du chat

14

Je voudrais concaténer la sortie de l'écho avec le contenu d'un fichier. J'ai essayé la commande suivante:

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

mais le 2.txtfichier contient uniquement le contenu de 1.txt. Pourquoi ça ne marche pas?

Ringger81
la source
3
Des programmes comme catlire uniquement à partir de l'entrée standard s'ils n'ont pas d'arguments de nom de fichier.
Barmar

Réponses:

23

Cela ne fonctionne pas car le catprogramme de votre séquence de tuyaux n'a pas été invité à lire la echosortie du programme à partir de l'entrée standard.

Vous pouvez utiliser -comme pseudo-nom de fichier pour indiquer une entrée standard dans cat. Depuis man catune installation msys2:

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

Alors essayez

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

au lieu.

mvw
la source
21

Comme indiqué par d'autres, votre commande d'origine échoue car ne cat 1.txttient pas compte de son entrée standard. Soit indiquer qu'il doit être son premier argument ( cat - 1.txt), soit utiliser la redirection de bloc pour rediriger echo abc et cat 1.txt ensemble. En être témoin:

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

Extrait pertinent du manuel ( man bash):

Commandes
composées Une commande composée est l'une des suivantes. Dans la plupart des cas, une liste dans la description d'une commande peut être séparée du reste de la commande par un ou plusieurs sauts de ligne et peut être suivie d'un saut de ligne à la place d'un point-virgule.

(liste)

    La liste est exécutée dans un environnement de sous-shell (voir ENVIRONNEMENT D'EXÉCUTION DE COMMANDE ci-dessous). Les affectations de variables et les commandes intégrées qui affectent l'environnement du shell ne restent pas en vigueur une fois la commande terminée. Le statut de retour est le statut de sortie de la liste.

{liste; }

    La liste est simplement exécutée dans l'environnement shell actuel.  la liste doit se terminer par une nouvelle ligne ou un point-virgule. C'est ce qu'on appelle une commande de groupe . Le statut de retour est le statut de sortie de la liste . Notez que, contrairement aux métacaractères (et ), {et }sont des mots réservés et doivent se produire lorsqu'un mot réservé est autorisé à être reconnu. Comme ils ne provoquent pas de rupture de mot, ils doivent être séparés de la liste par des espaces ou un autre métacaractère shell.

La première option (environnement sous-shell) a un tas d'effets secondaires, la plupart sinon tous sans rapport avec votre scénario; cependant, si la redirection d'un groupe de commandes est tout ce dont vous avez besoin, l'option # 2 ici (commande de groupe) est préférable.

Nubarke
la source
7
( echo "abc"; cat 1.txt ) > 2.txt

Vous avez canalisé la sortie d'écho vers cat, mais cat n'avait aucune utilité pour l'entrée et l'ignoriez. Maintenant, les commandes s'exécutent les unes après les autres, et leur sortie est groupée (les parenthèses) et dirigée dans 2.txt.

Gerard H. Pille
la source
1
Cette réponse peut être améliorée en expliquant comment cela fonctionne et pourquoi la tentative originale du PO ne fonctionne pas.
Bob
OK, j'ai essayé.
Gerard H.Pille
5
Un sous-shell n'est pas expressément requis ici, il serait peut-être préférable d'utiliser une commande de groupe. Voir ma réponse pour plus de détails.
Nubarke
Ah, mais je n'utiliserais jamais bash.
Gerard H.Pille
1
@ GerardH.Pille: Bien que la réponse de Daniel cite bash(1), elle décrit le comportement que chaque shell compatible POSIX doit prendre en charge.
G-Man dit `` Réintègre Monica '' le
2

Votre commande cat 1.txtne fait rien avec la sortie de echo "abc".

Au lieu de cela: (echo "abc"; cat 1.txt) > 2.txt écrira la sortie des deux commandes dans 2.txt.

muclux
la source
Cette réponse peut être améliorée en expliquant comment fonctionne l'alternative suggérée.
Bob
1

Dans n'importe quel shell POSIX, vous pouvez utiliser la substitution de commandes à utiliser cat filecomme entrée pour echo:

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

Dans Bash, vous pouvez utiliser la substitution de processus et utiliser l'écho comme un autre "fichier" pour cat, comme dans:

cat file1.txt <(echo This Too)

puis canalisez ou redirigez la sortie comme bon vous semble.

Comme toutes les autres réponses, cat ignore stdin s'il a un fichier à consulter. (J'aime aussi les réponses de Daniel & mvw, +1 pour eux)

Xen2050
la source
1
Cette réponse peut être améliorée en expliquant pourquoi la tentative initiale du PO ne fonctionne pas (et donc pourquoi cela est nécessaire à la place).
Bob
1
La <(command)construction est une extension bash. Ce n'est pas POSIX, vous ne pouvez donc pas vous y fier dans des scripts censés être exécutés avec /bin/sh.
Rhialto prend en charge Monica le
0

Juste une supposition, mais il semble que vous ayez un processus reproductible, ce qui est un bon candidat pour un alias ou une fonction. Les alias sont généralement des raccourcis pour appeler des commandes bash, telles que l'abréviation, sur un seul flux d'entrée comme argument / s.

alias hg="history | grep"

Cependant, dans ce cas, une fonction serait plus lisible, car vous combinez plusieurs flux d'entrée discrets (2) ainsi que plusieurs commandes bash. Vous avez deux arguments, le premier étant une chaîne et l'autre un chemin de fichier. En fin de compte, vous souhaitez que le résultat soit écrit dans le flux de sortie standard.

À partir d'une invite CLI, tapez ceci:

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

Votre fonction s'appelle ecat, ce qui est mémorable.

Vous pouvez maintenant invoquer

ecat "abc" 1.txt

Pour ajouter, fournissez simplement une destination de sortie différente à stdout:

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

L'opérateur de redirection d'ajout '>>' ajoutera la sortie à la fin du fichier spécifié.

Si vous l'aimez, ajoutez-le à votre fichier ~ / .bashrc pour le réutiliser.

declare -f ecat >> ~/.bashrc

Cela signifie également que vous pouvez décorer, etc., au sein de votre définition de fonction.

Aussi une bonne idée de protéger les fichiers contre l'écrasement en les ajoutant à votre ~ / .bashrc

set noclobber
FrDarryl
la source
2
Pour que votre fonction se comporte correctement, vous devez utiliser "$1"et "$2". Dans ce contexte, les accolades ne servent à rien. Voir ${name}ne signifie pas ce que vous pensez que cela fait… .
G-Man dit `` Réintègre Monica '' le
1
Comment la noclobbersuggestion répond-elle à la question posée? (Je ne suis pas non plus convaincu que ce soit un bon conseil - la modification du comportement global a tendance à casser les scripts / conseils / pratiques construits avec les valeurs par défaut à l'esprit).
Charles Duffy
0

Le code suivant fonctionnera également:

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

La sortie de echo abc sera ajoutée à 1.txt avec >> Après cela, le && lui dira d'exécuter le prochain ensemble de commandes qui cat 1.txt et le sortira ensuite à 2.txt . Fondamentalement, il ajoute la sortie de la première commande dans 1.txt, puis envoie la sortie de 1.txt dans 2.txt.

Si vous souhaitez que l'abc apparaisse en premier, vous pouvez utiliser le code suivant:

echo abc >> 2.txt && cat 1.txt >> 2.txt
Nasir Riley
la source
1
Cela va (1) mettre abcen bas de 2.txt; la question le veut tout en haut. (2)  modifier le 1.txtfichier; C'est inacceptable.
G-Man dit `` Réintègre Monica '' le
Où est-ce que ça dit? Ringger81 n'a jamais précisé où, dans 2.txt, il voulait que abc apparaisse. Vous supposez des choses que la question ne dit jamais.
Nasir Riley
(1) OK, vous soulevez un point valide sur # 1. Bien que la question mentionne «sortie de l'écho» avant «contenu d'un fichier» dans le texte, puis place l' echoavant avant catdans la commande exemple, je suppose qu'elle ne dit jamais exactement, explicitement , qu'elle veut la sortie de l'écho avant la contenu du fichier d'entrée. Il semble que la plupart des gens l'ont interprété de cette façon. (2)  1.txtest un fichier d'entrée. La question ne dit rien sur la modification 1.txt. Le fait que les fichiers d'entrée ne doivent pas être modifiés va de soi.
G-Man dit `` Réintègre Monica '' le
Je peux comprendre votre point de ne pas modifier le fichier imput. Mon deuxième code obtiendra l'effet souhaité sans le faire.
Nasir Riley
1
Ouvrir un fichier, l'ajouter, le fermer , l'ouvrir à nouveau, l'ajouter à nouveau ... pourquoi faire cela plutôt que de l'ouvrir une seule fois et de conserver la redirection en place pour les deux opérations?
Charles Duffy