ne ligne commençant avec Fred Flintstone doit être ajouté avec une chaîne. Recherchez l'occurrence spécifiée de Fred Flintstone et ajoutez-la.
Comment utiliser cette commande pour n'importe laquelle des occurrences d'un tel modèle? j'ai essayé
sed '/Fred Flintstone/ s/$/ someString/2' filename
Apparemment, le précédent ne fonctionne pas. Cela fonctionne bien pour toutes les occurrences, mais pas pour une occurrence spécifique. (Disons que je veux remplacer le premier ou le deuxième ou le troisième [n'importe lequel])
Exemple de fichier1:
Fred Flintstone
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark
Fichier de sortie souhaité 1:
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
Bien que vous ayez mentionné sed
name__, il s’agit en quelque sorte de awk
name __- y tâches:
awk -v pat="Fred Flintstone" '$0 ~ pat {count++;\
if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
-v pat="Fred Flintstone"
enregistre le motif Regex correspondant en tant que variable pat
à utiliser dans les expressions awk
name__
$0 ~ pat
vérifie l'enregistrement avec pat
pour une correspondance; si elle correspond, la variable count
est augmentée de 1 et si count
vaut 2, l'enregistrement est réinitialisé avec le contenu actuel plus someString
({count++; if (count == 2) { $0 = $0" someString" ;} ;}
)
1 est un idiome; comme il est vérité , tous les enregistrements seront imprimés
Exemple:
% cat file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark
% awk -v pat="Fred Flintstone" '$0 ~ pat {count++; if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
Cette simple commande sed
vous permet d'effectuer la modification de manière sélective sans utiliser de boucles (elle utilise une branche à la fin) ou nécessitant des extensions GNU ou lire le fichier entier à la fois:
sed -r '/Fred Flintstone/ {x; s/$/#/; /^#{2}$/ {x; s/.*/& someString/; b}; x}'
Explication:
-r
- utilise l'expression régulière étendue/Fred Flintstone/
- pour les lignes correspondant à ce modèle: x
- échange un espace modèle et le maintient (active le compteur)s/$/#/
- ajoute un caractère au compteur/^#{2}$/
- lorsque le compteur a la longueur 2 (remplacez une valeur) x
échange le motif et le garde (active la ligne d'entrée comptée)s/.*/& someString/
- ajoute la chaîne à la ligne souhaitéeb
- passe à la fin du traitement de cette ligne afin qu'elle puisse être impriméex
- échange l'espace de modèle et le maintient (active les lignes qui correspondent à la chaîne mais pas au compte)Les niveaux d'indentation dans l'explication indiquent les niveaux d'imbrication d'accolades.
Toutes les autres lignes passent sans traitement et sont imprimées.
Réponse révisée pour empêcher l’injection de code sur les barres obliques inverses ainsi que les barres obliques, guillemets lorsqu’il utilise awk les variables awk -v variable ...
ou un shell awk '...' variable="$value"
depuis awk effectue le traitement de la séquence d'échappement C sur les valeurs transmises avec -v variable=
ou Shell variable=$value
; donc le Shell variable='\\n'
deviendra \n
dans awk ).
pattern="${patt//\\/\\\\}" awk '
$0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 "something"};1' infile
pour l'entrée ci-dessous et le motif :
another break line
Johnson Stone
\"Fred //\\Flintstone' SOMETHING will goes here ...
\"Fred //\\Flintstone'
Michael Clark
le motif est dans une variable appelée patt
name__
$ echo "$patt"
\"Fred //\\Flintstone'
La sortie est:
\"Fred //\\Flintstone'
another break line
Johnson Stone
\"Fred //\\Flintstone' SOMETHING will goes here ...something
\"Fred //\\Flintstone'
Michael Clark
Ce pattern="${patt//\\/\\\\}"
échappe à toutes les barres obliques inverses de la variable $patt
, car [ "the '~' operator does pattern matching, treating the right hand operand as an (extended) regular expression, and the left hand one as a string
" par mur ], vous devrez vous échapper tous les caractères spéciaux dans les ERE alors.
Ce $0 ~ ENVIRON["pattern"]{ seen++ }
vérifie si la ligne en cours correspond au pattern
name__, puis incrémente le précieux seen++
une fois.
Ce seen==2 { $0 = $0 "something"}'
vérifie si la deuxième ligne a été mise en correspondance avec le pattern
du résultat ci-dessus (maintenant seen==2
), puis ajoute la chaîne "somestring" à la fin de cette ligne.
Le 1
(ou toute instruction True) à la fin active awk l’impression par défaut.
plus tard, vous devrez peut-être passer la chaîne something
en tant que variable, et vous devrez utiliser quelque chose comme edit=$somesting
et y utiliser ENVIRON["edit"]
.
pattern="${patt//\\/\\\\}" edit="$something" awk '
$0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 ENVIRON["edit"]};1' infile
Voici un moyen de le faire dans sed
sans mettre en mémoire le fichier entier:
N
à l'espace du motifTa
$q
quitte la boucle si la fin du fichier est atteinte sans correspondance.
Alors
sed '/Fred Flintstone/ {:a; $q; N; s//& someString/2; Ta;}' File1
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
Bien que T
soit une extension GNU, vous pouvez faire de même dans POSIX sed
en utilisant t; ba
Hmm ... après y avoir réfléchi un peu plus, le nouveau texte sera ajouté à toutes les autres occurrences - pas seulement à la seconde. Si vous devez vraiment utiliser ne remplacer que la deuxième occurrence, la seule façon pour moi de le faire serait:
GNU sed
fournit une astuce pour adresser la première instance d'un motif
0,/pattern/
Alors
sed -e '0,/Fred Flintstone/ s//Barney Rubble/' \
-e '0,/Fred Flintstone/ s//& someString/' \
-e '0,/Barney Rubble/ s//Fred Flintstone/
' File1
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
Si cela ne vous dérange pas d'utiliser ed, vous pouvez vous adresser plus directement à la seconde instance en allant sur la première ligne, puis en faisant correspondre le transfert d'une instance à la suivante:
ed -s File1 << \EOF
1;#
/Fred Flintstone/,/Fred Flintstone/ s//& someString/
,p
q
EOF
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
ou comme une ligne
printf '1;#\n/Fred Flintstone/,/Fred Flintstone/ s//& someString/\n,p\n' | ed -s File1
Vous pouvez rendre la version ed sur place en remplaçant ,p
par w
ex
, l'éditeur de fichier spécifié par POSIX(C'est le prédécesseur de vi
et fait toujours partie de vi
.)
printf '%s\n' '0/Fred Flintstone///s/$/ someString/' x | ex filename
La magie est que contrairement à Sed, Awk et à des outils similaires, ex
ne fait pas exécuter de code sur toutes les lignes. Vous pouvez déplacer le curseur, donner des commandes, etc.
Dans ce cas, nous donnons un numéro de ligne 0
(qui garantit que Fred Flintstone sera pris en compte sur la première ligne), suivi d'un regex /Fred Flintstone/
qui fait référence à la première ligne du fichier correspondant à cette regex, suivie d'un autre regex //
qui, étant vide, réutilise la dernière expression rationnelle et renvoie donc à la deuxième seconde ligne du fichier qui correspond; Nous utilisons ensuite la commande s
que vous connaissez déjà.
La commande x
signifie enregistrer toutes les modifications et quitter.
Nous utilisons printf
pour alimenter les commandes en ex
.