Utilisation de la sortie provenant de sed

J’ai une commande sed qui capture une seule ligne avec sometext. La ligne du fichier qu’il capture se termine par un saut de ligne. J’essaie d’utiliser cette variable dans un pipeline, cependant, lorsque je tente de faire écho ou de l’utiliser avec d’autres commandes nécessitant une entrée, le résultat est un blanc. Ex: sed '1,1!d' somefile.txt | echo "$1" sed '1,1!d' somefile.txt | echo "$1" , je sais que la variable elle-même n’est pas vide car je peux remplacer echo "$1" par le cat $1 et voir la bonne impression.

edit – J’ai essayé de passer à une tr -d et de supprimer la nouvelle ligne. J’ai confirmé que le caractère de nouvelle ligne avait disparu, mais les échos sont toujours vides. Les chats ne le font pas.

edit 2 – J’ai introduit la variable dans une instruction if ... | if [[ -z $1 ]]; then cat $1; fi ... | if [[ -z $1 ]]; then cat $1; fi Si elle touche le si, est déterminée à être vide, lance le chat, qui imprime une ligne non vide à la console. Si la variable est vide, pourquoi le chat imprime-t-il toujours des informations?

Quelle est la cause de cette incohérence et comment puis-je résoudre mon problème? Le but ultime est d’exécuter la sortie d’un sed, via un autre pour remplacer des lignes spécifiques dans un fichier cible.

sed '1,1!d' somefile.txt | sed '2,1s/.*/'$1'/' targetfile.txt

Contenu de somefile.txt:

 these are words 

Contenu de targetfile.txt:

 The next line should say these This line should say these The previous line should say these 

Sortie de l’écho après sed:

  

Sortie de chat après sed:

 these 

Sortie de 2ème sed, en utilisant l’entrée du 1er:

 The next line should say these the previous line should say these 

Vous êtes confus au sujet des arguments et des données d’entrée. Regarde ça:

 $ echo "$1" $ echo "foo" | if [[ -z $1 ]]; then cat $1; fi foo 

Le premier argument de mon shell, $1 est vide if [[ -z $1 ]] réussit. La raison pour laquelle cat $1 produit une sortie est que vous avez une erreur de programmation shell fondamentale dans cette instruction – vous ne citez pas votre variable, $1 . La syntaxe correcte n’est pas le cat $1 , c’est le cat "$1" . Regardez la différence:

 $ echo "foo" | if [[ -z $1 ]]; then cat "$1"; fi cat: '': No such file or directory 

Nous pouvons simplifier le code pour rendre plus clair ce qui se passe:

 $ echo "foo" | cat $1 foo $ echo "foo" | cat "$1" cat: '': No such file or directory 

La raison qui fait echo "foo" | cat $1 echo "foo" | cat $1 produit une sortie, c’est que le $ 1 non coté est élargi par le shell à rien avant que cat soit appelé, donc cette instruction est équivalente à simplement echo "foo" | cat echo "foo" | cat and so cat ne fait que copier l’entrée provenant de la pipe vers sa sortie.

D’un autre côté, echo "foo" | cat "$1" echo "foo" | cat "$1" génère une erreur car le shell développe "$1" à la chaîne null avant que cat soit appelé, il demande alors à cat d’ouvrir un fichier nommé et cela n’existe bien sûr pas, d’où l’erreur.

Citez toujours vos variables shell à moins que vous n’ayez une raison spécifique pour ne pas comprendre et comprendre toutes les implications. Lisez une page de gestion de shell et / ou google si vous ne savez pas quelles sont ces implications.

Avec une autre partie de votre code, vous avez:

 sed '1,1!d' somefile.txt | echo "$1" 

mais, contrairement à cat , echo ne lit pas les entrées d’un tube ni d’un nom de fichier passé en argument. L’entrée de echo est juste la liste des arguments de chaîne que vous lui fournissez alors que echo "foo" | cat echo "foo" | cat fera que cat lise le stream d’entrée contenant foo et le restitue, echo "foo" | echo echo "foo" | echo ne produira aucune sortie car echo n’est pas conçu pour lire les entrées d’un tube et il suffira donc d’imprimer une chaîne nulle puisque vous ne lui avez donné aucun argument.

Ce que vous essayez vraiment d’accomplir n’est pas clair, mais je pense que vous pourriez vouloir remplacer la 2ème ligne de targetfile.txt par la première ligne de somefile.txt . Si oui, c’est juste:

 awk ' NR==FNR { if (NR==1) new=$0; next } FNR==2 { $0 = new } { print } ' somefile.txt targetfile.txt 

N’essayez pas d’utiliser sed pour le faire ou vous vous retrouverez à échapper / citer hell car, contrairement à awk, sed ne comprend pas les chaînes littérales, voir Est-il possible d’échapper de manière fiable aux méta-caractères regex avec sed .

Vous semblez vouloir extraire la première ligne du file1 et l’utiliser pour remplacer la deuxième ligne du file2 .

Pour le moment, vous extrayez cette valeur du premier fichier avec votre première sed mais vous l’envoyez au second sed sur son stdin plutôt qu’en tant que paramètre ( $1 ).

Votre description est déroutante alors je vais l’utiliser comme file1 :

 File 1 Line 1 File 1 Line 2 File 1 Line 3 

Et ceci comme file2 :

 File 2 Line 1 File 2 Line 2 File 2 Line 3 

Il y a plusieurs façons de le faire.


Méthode 1

 # Extract line1 from file1 extracted=$(sed '1!d' file1) # Replace line 2 in file2 with extracted value sed "2s/.*/$extracted/" file2 

Je ne sais pas pourquoi je me sens comme un dentiste maintenant 🙂

Si vous voulez tout mettre sur une seule ligne, comme certains aiment le faire:

 x=$(sed '1!d' file1) && sed "2s/.*/$x/" file2 

Méthode 2

Celui-ci est un peu difficile. Il utilise le premier sed pour écrire un script pour la deuxième sed :

 sed 's/^/2s|.*|/;s/$/|/;q' file1 | sed -f /dev/stdin file2 

Si vous regardez le premier sed seul, vous verrez qu’il génère un script pour le second:

 sed 's/^/2s|.*|/;s/$/|/;q' file1 2s|.*|File 1 Line 1| 

Si vous regardez la deuxième sed , vous verrez qu’elle exécute un script transmis sur son entrée standard :

 sed -f /dev/stdin ... 

Méthode 3

Plus facile encore est awk :

 awk 'FNR==NR{if(NR==1)saved=$0;next} FNR==2{$0=saved}1' file1 file2 File 2 Line 1 File 1 Line 1 File 2 Line 3 

Tout ce que vous devez noter est que je passe 2 fichiers à awk et que FNR==NR dans le script signifie que awk traite actuellement le premier fichier, car FNR est le numéro de ligne dans le fichier actuel et NR est le nombre total de fichiers. les lignes awk ont été traitées depuis tous les fichiers. Ainsi, lors du traitement du second fichier, NR est supérieur à FNR par le nombre de lignes du premier fichier.