web-dev-qa-db-fra.com

Comment remplacer une ligne entière dans un fichier texte par un numéro de ligne

J'ai une situation où je veux un script bash pour remplacer une ligne entière dans un fichier. Le numéro de ligne est toujours le même, il peut donc s'agir d'une variable codée en dur.

Je n'essaie pas de remplacer une sous-chaîne dans cette ligne, je veux juste remplacer cette ligne entièrement par une nouvelle ligne.

Y at-il des méthodes bash pour faire cela (ou quelque chose de simple qui peut être jeté dans un script .sh).

136
user788171

Pas le meilleur, mais ça devrait marcher:

sed -i 'Ns/.*/replacement-line/' file.txt

N devrait être remplacé par votre numéro de ligne cible. Ceci remplace la ligne dans le fichier d'origine. Pour enregistrer le texte modifié dans un autre fichier, supprimez l'option -i:

sed 'Ns/.*/replacement-line/' file.txt > new_file.txt
196
chepner

En fait, j'ai utilisé ce script pour remplacer une ligne de code dans le fichier cron sur les serveurs UNIX de notre société il y a quelque temps. Nous l'avons exécuté en tant que script shell normal et nous n'avons eu aucun problème:

#Create temporary file with new line in place
cat /dir/file | sed -e "s/the_original_line/the_new_line/" > /dir/temp_file
#Copy the new file over the original file
mv /dir/temp_file /dir/file

Cela ne va pas par numéro de ligne, mais vous pouvez facilement passer à un système basé sur le numéro de ligne en mettant le numéro de ligne avant le s/ et en plaçant un caractère générique à la place de the_original_line.

42
Kyle

Supposons que vous souhaitiez remplacer la ligne 4 par le texte "différent". Vous pouvez utiliser AWK comme ceci:

awk '{ if (NR == 4) print "different"; else print $0}' input_file.txt > output_file.txt

AWK considère que l'entrée est "des enregistrements" divisés en "champs". Par défaut, une ligne correspond à un enregistrement. NR est le nombre d'enregistrements vus. $0 représente l'enregistrement complet en cours (tandis que $1 est le premier champ de l'enregistrement et ainsi de suite; par défaut, les champs sont des mots de la ligne).

Donc, si le numéro de ligne actuel est 4, affichez la chaîne "différente" mais sinon, affichez la ligne sans modification.

Dans AWK, le code de programme inclus dans { } ne s'exécute qu'une fois sur chaque enregistrement d'entrée.

Vous devez citer le programme AWK entre guillemets pour empêcher le shell d’essayer d’interpréter des éléments tels que le $0.

EDIT: Un programme AWK plus court et plus élégant de @chepner dans les commentaires ci-dessous:

awk 'NR==4 {$0="different"} { print }' input_file.txt

Remplacez l’enregistrement complet par la chaîne "différente" uniquement pour l’enregistrement (ligne) du numéro 4. Ensuite, pour chaque enregistrement d'entrée, imprimez-le.

Clairement mes compétences AWK sont rouillées! Merci, chepner.

EDIT: et voyez aussi une version encore plus courte de @Dennis Williamson:

awk 'NR==4 {$0="different"} 1' input_file.txt

Comment cela fonctionne est expliqué dans les commentaires: le 1 évalue toujours la valeur true et le bloc de code associé est toujours exécuté. Mais il n'y a pas de bloc de code associé, ce qui signifie qu'AWK effectue son action par défaut en imprimant simplement la ligne entière. AWK est conçu pour permettre des programmes laconiques comme celui-ci.

19
steveha

Étant donné ce fichier de test (test.txt)

Lorem ipsum dolor sit amet,
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus.

la commande suivante remplacera la première ligne par "newline text"

$ sed '1 c\
> newline text' test.txt

Résultat:

newline text
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus.

plus d'informations peuvent être trouvées ici

http://www.thegeekstuff.com/2009/11/unix-sed-tutorial-append-insert-replace-and-count-file-lines/

14
Eric Robinson

en bash, remplacez N, M par les numéros de ligne et xxx yyy par ce que vous voulez

i=1
while read line;do
  if((i==N));then
    echo 'xxx'
  Elif((i==M));then
    echo 'yyy'
  else
    echo "$line"
  fi
  ((i++))
done  < orig-file > new-file

MODIFIER

En fait, dans cette solution, il y a quelques problèmes, avec les caractères "\ 0", "\ t" et "\"

"\ t", peut être résolu en mettant IFS = avant de lire: "\", en fin de ligne avec -r

IFS= read -r line

mais pour "\ 0", la variable est tronquée, il n'y a pas de solution dans pure bash: Affecter une chaîne contenant un caractère nul (\ 0) à une variable dans Bash Mais dans un fichier texte normal, aucun caractère nul\0

Perl serait un meilleur choix

Perl -ne 'if($.==N){print"xxx\n"}elsif($.==M){print"yyy\n"}else{print}' < orig-file > new-file
7
Nahuel Fouilleul
# Replace the line of the given line number with the given replacement in the given file.
function replace-line-in-file() {
    local file="$1"
    local line_num="$2"
    local replacement="$3"

    # Escape backslash, forward slash and ampersand for use as a sed replacement.
    replacement_escaped=$( echo "$replacement" | sed -e 's/[\/&]/\\&/g' )

    sed -i "${line_num}s/.*/$replacement_escaped/" "$file"
}
3
Daniel Bigham

Excellente réponse de Chepner. Cela fonctionne pour moi à bash Shell.

 # To update/replace the new line string value with the exiting line of the file
 MyFile=/tmp/ps_checkdb.flag

 `sed -i "${index}s/.*/${newLine}/" $MyFile`

ici
index - Numéro de ligne
newLine - nouvelle chaîne que nous souhaitons remplacer.


De même, le code ci-dessous est utilisé pour lire une ligne particulière du fichier. Cela n'affectera pas le fichier réel.

LineString=`sed "$index!d" $MyFile` 

ici
!d - supprimera les lignes autres que la ligne no $index Nous obtiendrons donc le résultat sous forme de chaîne de caractères non associée à $index dans le fichier.

2
Kanagavelu Sugumar

Sur mac j'ai utilisé

sed -i '' -e 's/text-on-line-to-be-changed.*/text-to-replace-the=whole-line/' file-name
1
nakeer