Changer le text sur un seul numéro de ligne dans plusieurs files text

Supposons que j'ai dix scripts shell bash: script1.sh , script2.sh , …, script10.sh . Initialement, les dix files sont identiques.

Maintenant, j'aimerais faire deux changements dans chaque script:

  1. Dans chaque file, je voudrais changer une ligne particulière (c'est-à-dire la ligne 8), c'est-à-dire supprimer tout ce qui se trouve à la ligne 8 et le replace par une string «constante» que je précise "This is line 8." Ceci est similaire à cette question , mais ils voulaient replace "AAA" par "BBB" , alors que je voudrais replace la ligne 8 (quelle qu'elle soit) par "This is line 8." .

  2. Dans chaque file, je voudrais changer une autre ligne particulière (disons la ligne 21) et la replace par une string "variable" que je spécifie. Par exemple, dans script1.sh je veux changer la ligne 21 en "XYZ" ; dans script2.sh Je veux changer la ligne 21 en "PQR" ; et dans script3.sh je veux changer la ligne 21 en "ABC" . Il s'agit essentiellement de nombreux appels à la fonction de (1) ci-dessus – sauf que je ferais la modification dans un file individuel plutôt que dans tous les files, et que je spécifie dix strings différentes plutôt qu'une seule. Donc, pour get (2) ici, peut-être j'appellerais juste (1) dix fois différentes avec des parameters différents.

Je suis intéressé par les solutions qui utilisent des programmes Linux couramment disponibles comme bash , vi , awk , gawk , etc.

 for file in f1 f2; do sed -i '8s/^.*$/foo/' "$file" done 

Utiliser awk

 for file in script1.sh script2.sh script3.sh ... script10.sh; do temp=$(mktemp) awk ' BEGIN { line8 = "This is line 8" line21["script1.sh"] = "XYZ" line21["script2.sh"] = "PQR" line21["script3.sh"] = "ABC" # ... } FNR == 8 { print line8; next } FNR == 21 && FILENAME in line21 { print line21[FILENAME]; next } {print} ' "$file" > "$temp" && mv "$temp" "$file" done 

ou, en utilisant bash et sed

 # bash variables to store new values. requires bash v4 for the associative array line8="This is line 8" declare -A line21=( [script1.sh]="XYZ" [script2.sh]="PQR" [script3.sh]="ABC" # ... ) # then use sed for file in script1.sh script2.sh script3.sh ... script10.sh; do sed -i "8s/.*/$line8/; 21s/.*/${line21[$file]}/" "$file" done 

Avec la solution sed, vous devez faire attention que les nouvelles lignes ne contiennent pas de caractères "/", car cela brisera la command // //. Bien que vous puissiez utiliser différents caractères de délimitation, tels que s|pattern|replacement| (auquel cas le même avertissement s'applique, récursivement)

ed fonctionne aussi:

 for file in script1.sh script2.sh script3.sh ... script10.sh; do ed "$file" <<ED_COMMANDS 8d 8i $line8 . 21d 21i ${line21[$file]} . w q ED_COMMANDS done 

Je vais répondre aux deux questions mais, en règle générale, s'il vous plaît, ne combinez pas de questions comme celle-ci, divisez-les en deux posts séparés.

question 1

  1. Perl:

     for f in *.sh; do perl -i -lne '$.==8 ? print "This is line 8" : print;' "$f"; done 
  2. awk et variantes:

     for f in *.sh; do awk '{if(NR==8){print "This is line 8"}else{print}}' "$f" > fifo && mv fifo "$f"; done 

question 2

Je voudrais d'abord créer un file avec les rlocations que je veux faire. Par exemple:

 script1.sh foo1 script2.sh foo2 script3.sh foo3 script4.sh foo4 

Lisez ensuite ce file pour effectuer les substitutions:

 while read fs; do export s; perl -i -lne '$.==8 ? print "$ENV{s}" : print;' "$f"; done < sublist.txt