web-dev-qa-db-fra.com

Comment remplacer une chaîne sur la 5ème ligne de plusieurs fichiers texte?

Je souhaite remplacer la 5ème ligne de plusieurs fichiers texte (fichier1.txt, fichier2.txt, fichier3.txt, fichier4.txt) par la chaîne "Good Morning" à l'aide d'une seule commande de terminal.

Tous les fichiers texte se trouvent sur mon ~/Desktop.

Remarque: Mon bureau est constitué de 6 fichiers .txt. Je souhaite appliquer la modification aux 4 fichiers texte susmentionnés uniquement.

22
Avinash Raj

Voici quelques approches. J'utilise extension d'accolade (file{1..4}.txt), ce qui signifie file1.txt file2.txt file3.txt file4.txt

  1. Perl

    Perl -i -pe 's/.*/ Good Morning / if $.==5' file{1..4}.txt
    

    Explication:

    • -i: permet à Perl de modifier les fichiers en place, en modifiant le fichier d'origine.

      Si -i est suivi d'un suffixe d'extension de fichier, une sauvegarde est créée pour chaque fichier modifié. Ex: -i.bak crée un file1.txt.bak si file1.txt est modifié pendant l'exécution.

    • -p: signifie lire le fichier d'entrée ligne par ligne, appliquer le script et l'imprimer.

    • -e: permet de passer un script à partir de la ligne de commande.

    • s/.*/ Good Morning /: cela remplacera le texte de la ligne actuelle (.*) par Good Morning.

    • $. est une variable Perl spéciale qui contient le numéro de ligne actuel du fichier d'entrée. Ainsi, s/foo/bar/ if $.==5, signifie remplacer foo par bar uniquement sur la 5ème ligne.

  2. sed

    sed -i '5s/.*/ Good Morning /' file{1..4}.txt
    

    Explication:

    • -i: Comme pour Perl, éditez le fichier à la place.

    Par défaut, sed imprime chaque ligne du fichier d'entrée. Le 5s/pattern/replacement/ signifie un modèle de remplacement avec remplacement sur la 5ème ligne.

  3. Awk

    for f in file{1..4}.txt; do 
        awk 'NR==5{$0=" Good Morning "}1;' "$f" > foobar && mv foobar "$f"; 
    done
    

    Explication:

    awk n'a pas d'équivalent à -i option¹, ce qui signifie que nous devons créer un fichier temporaire (foobar) qui est ensuite renommé pour écraser l'original. La boucle bash for f in file{1..4}.txt; do ... ; done passe simplement dans chacun des file{1..4}.txt, en enregistrant le nom du fichier actuel sous le nom $f. Dans awk, NR est le numéro de la ligne en cours et $0 est le contenu de la ligne en cours. Ainsi, le script remplacera la ligne ($0) par "Good Morning" uniquement sur la 5ème ligne. 1; est awk pour "print the line".

    ¹Les nouvelles versions font comme devnull l'a montré dans son réponse .

  4. coreutils

    for f in file{1..4}.txt; do 
        (head -4 "$f"; echo " Good Morning "; tail -n +6 "$f") > foobar && 
        mv foobar "$f"; 
    done 
    

    Explication:

    La boucle est expliquée dans la section précédente.

    • head -4: affiche les 4 premières lignes

    • echo " Good Morning ": print "Good Morning"

    • tail -n +6: affiche tout depuis la 6ème ligne jusqu'à la fin du fichier

    Les parenthèses ( ) autour de ces trois commandes vous permettent de capturer la sortie des trois (donc, les 4 premières lignes, puis "Bonjour", puis le reste des lignes) et de les rediriger vers un fichier.

39
terdon

Vous pouvez utiliser sed:

sed '5s/^/Good morning /' file

ajouterait Good morning à la cinquième ligne d'un fichier.

Si vous souhaitez plutôt remplacer le contenu de la ligne 5, dites:

sed '5s/.*/Good morning/' file

Si vous souhaitez enregistrer les modifications dans le fichier, utilisez l'option -i:

sed -i '5s/.*/Good morning/' file

sed peut gérer plusieurs fichiers à la fois. Vous pouvez simplement ajouter d'autres noms de fichiers à la fin de la commande. Vous pouvez également utiliser les extensions bash pour faire correspondre des fichiers particuliers:

# manually specified
sed -i '5s/.*/Good morning/' file1.txt file2.txt file3.txt file4.txt

# wildcard: all files on the desktop
sed -i '5s/.*/Good morning/' ~/Desktop/*

# brace expansion: file1.txt, file2.txt, file3.txt, file4.txt
sed -i '5s/.*/Good morning/' file{1..4}.txt

Vous pouvez en savoir plus sur les expansions d'accolades ici .


Les versions 4.1.0 et supérieures de GNU awk sont accompagnées de ne extension qui permet l’édition sur place. Pour que vous puissiez dire:

gawk -i inplace 'NR==5{$0="Good morning"}7' file

remplacer la ligne n ° 5 dans le fichier par Good morning!

23
devnull

Je n'ai pas vu la solution python alors le voici:

import sys
import os
def open_and_replace(filename):

    with open(filename) as read_file:
        temp = open("/tmp/temp.txt","w")
        for index,line in enumerate(read_file,1):
            if  index == 5:
                temp.write("NEW STRING\n")
            else:
                temp.write(line.strip() + "\n")
        temp.close()
    os.rename("/tmp/temp.txt",filename)

for file_name in sys.argv[1:]:
    open_and_replace(file_name)

L'idée de base est que pour chaque fichier fourni sur la ligne de commande en tant qu'argument, nous écrivons un fichier temporaire et énumérons chaque ligne du fichier d'origine. Si l'indice de la ligne est 5, nous écrivons une ligne différente. Le reste ne fait que remplacer l'ancien fichier par un fichier temporaire. Démo:

$> ls
file1.txt  file2.txt  file3.txt
$> cat file1.txt                                                               
line 1
line 2
line 3
line 4
GOOD MORNING
line 6
$> python ~/replace_5th_line.py file1.txt file2.txt  file3.txt                 
$> cat file1.txt                                                               
line 1
line 2
line 3
line 4
NEW STRING
line 6
$> cat file2.txt                                                               
line 1
line 2
line 3
line 4
NEW STRING
line 6

La même chose peut être obtenue avec une compréhension de liste. Ci-dessous, une ligne du même script:

cat /etc/passwd | python -c 'import sys; print "\n".join(["CUSTOM"  if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])'

ou sans cat

python -c 'import sys; print "\n".join(["CUSTOM"  if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])' < /etc/passwd

Il ne reste plus qu'à rediriger la sortie du contenu édité dans un autre fichier avec > output.txt

2

Vous pouvez utiliser Vim en mode Ex:

for b in 1 2 3 4
do
  ex -sc '5c|Good Morning' -cx file"$b".txt
done
  1. 5 sélectionnez 5ème ligne

  2. c remplacer le texte

  3. x écrire si des modifications ont été apportées (elles l’ont fait) et quitter

1
Steven Penny

Ce qui suit est un script bash qui termine le processus Perl suggéré dans cette réponse

Exemple:

/tmp/it

console:
  enabled:false

Puis lancez ce qui suit:

$ search_and_replace_on_line_of_file.sh false true 2 /tmp/it

et le fichier contient maintenant

/tmp/it

console:
  enabled:true

search_and_replace_on_line_of_file.sh

function show_help()
{
  IT=$(CAT <<EOF

  usage: SEARCH REPLACE LINE_NUM FILE

  e.g. 

  false true 52 /tmp/it  -> replaces false with true on line 52 of file /tmp/it

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$4" ]
then
  show_help
fi

SEARCH_FOR=$1
REPLACE_WITH=$2
LINE_NO=$3
FILE_NAME=$4
Perl -i -pe "s/$SEARCH_FOR/$REPLACE_WITH/ if $.==$LINE_NO" $FILE_NAME 
0
brad parks