Comment utiliser sed pour supprimer toutes les lignes d'un fichier texte contenant une chaîne spécifique?
Comment utiliser sed pour supprimer toutes les lignes d'un fichier texte contenant une chaîne spécifique?
Réponses:
Pour supprimer la ligne et imprimer la sortie en sortie standard:
sed '/pattern to match/d' ./infile
Pour modifier directement le fichier - ne fonctionne pas avec BSD sed:
sed -i '/pattern to match/d' ./infile
Idem, mais pour BSD sed (Mac OS X et FreeBSD) - ne fonctionne pas avec GNU sed:
sed -i '' '/pattern to match/d' ./infile
Pour modifier directement le fichier (et créer une sauvegarde) - fonctionne avec BSD et GNU sed:
sed -i.bak '/pattern to match/d' ./infile
sed '/pattern to match/d' ./infile > ./newfile
ou si vous voulez faire une modification sur place, vous pouvez ajouter le -i
drapeau à sed comme dans sed -i '/pattern to match/d' ./infile
. Notez que le -i
drapeau nécessite GNU sed et n'est pas portable
sed -i.backup '/pattern to match/d' ./infile
) Cela m'a permis de faire des modifications sur place.
sed
à tous les fichiers dont la version n'est pas contrôlée.
sed -i '' '/pattern/d' ./infile
.
Il existe de nombreuses autres façons de supprimer des lignes avec une chaîne spécifique en plus sed
:
awk '!/pattern/' file > temp && mv temp file
ruby -i.bak -ne 'print if not /test/' file
perl -ni.bak -e "print unless /pattern/" file
while read -r line
do
[[ ! $line =~ pattern ]] && echo "$line"
done <file > o
mv o file
grep -v "pattern" file > temp && mv temp file
Et bien sûr sed
(l'impression de l'inverse est plus rapide que la suppression réelle):
sed -n '/pattern/!p' file
sed
exemple a un comportement différent, il ne fait que greps! ça devrait être quelque chose comme ça sed -n -i '/pattern/!p' file
.
grep -v "pattern" file > temp; mv temp file
cela peut s'appliquer à certains des autres exemples en fonction de la valeur de retour.
seq -f %f 10000000 >foo.txt
. sed d: time sed -i '' '/6543210/d' foo.txt
réel 0m9.294s. sed! p: time sed -i '' -n '/6543210/!p' foo.txt
réel 0m13.671s. (Pour les fichiers plus petits, la différence est plus grande.)
Vous pouvez utiliser sed pour remplacer les lignes en place dans un fichier. Cependant, il semble être beaucoup plus lent que d'utiliser grep pour l'inverse dans un deuxième fichier, puis de déplacer le deuxième fichier sur l'original.
par exemple
sed -i '/pattern/d' filename
ou
grep -v "pattern" filename > filename2; mv filename2 filename
La première commande prend de toute façon 3 fois plus de temps sur ma machine.
sed '/pattern/d' filename > filename2; mv filename2 filename
Le moyen facile de le faire, avec GNU sed
:
sed --in-place '/some string here/d' yourfile
-r
option (ou -E
, selon votre version). Cela permet l'utilisation de métacaractères regex +
, ?
, {...}
et (...)
.
Vous pouvez envisager d'utiliser ex
(qui est un éditeur standard basé sur les commandes Unix):
ex +g/match/d -cwq file
où:
+
exécute la commande Ex donnée ( man ex
), identique à celle -c
qui s'exécute wq
(écrire et quitter)g/match/d
- Commande Ex pour supprimer les lignes avec données match
, voir: Puissance de gL'exemple ci-dessus est une méthode compatible POSIX pour la modification sur place d'un fichier conformément à ce message dans les spécifications ex
Unix.SE et POSIX pour .
La différence avec sed
est que:
sed
est un éditeur S tream ED , pas un éditeur de fichiers. BashFAQ
Sauf si vous appréciez le code non transférable, les frais généraux d'E / S et certains autres effets secondaires néfastes. Donc, fondamentalement, certains paramètres (tels que in-place / -i
) sont des extensions FreeBSD non standard et peuvent ne pas être disponibles sur d'autres systèmes d'exploitation.
man ex
cela me donne l'homme pour vim
, il semble que cela ex
fait partie de vim ... si j'ai bien compris, cela signifie que la syntaxe du modèle match
est vimregex.com qui est similaire mais différent des saveurs POSIX et PCRE?
:g
est une commande compatible POSIX avec quelques légères différences . Je suppose que PCRE était basé sur cela.
J'avais du mal avec ça sur Mac. De plus, je devais le faire en utilisant le remplacement variable.
J'ai donc utilisé:
sed -i '' "/$pattern/d" $file
où $file
est le fichier où la suppression est nécessaire et $pattern
est le modèle à associer pour la suppression.
J'ai choisi le ''
de ce commentaire .
La chose à noter ici est l' utilisation de guillemets doubles dans "/$pattern/d"
. La variable ne fonctionnera pas lorsque nous utilisons des guillemets simples.
sed
nécessite un paramètre après -i
, donc si vous ne voulez pas de sauvegarde, vous devez toujours ajouter une chaîne vide:-i ''
sed -i "/$pattern/d" $file
. Merci pour votre réponse.
J'ai fait un petit benchmark avec un fichier qui contient environ 345 000 lignes. Le chemin avec grep
semble être environ 15 fois plus rapide que la sed
méthode dans ce cas.
J'ai essayé à la fois avec et sans le réglage LC_ALL = C, il ne semble pas changer les temps de manière significative. La chaîne de recherche (CDGA_00004.pdbqt.gz.tar) se situe quelque part au milieu du fichier.
Voici les commandes et les horaires:
time sed -i "/CDGA_00004.pdbqt.gz.tar/d" /tmp/input.txt
real 0m0.711s
user 0m0.179s
sys 0m0.530s
time perl -ni -e 'print unless /CDGA_00004.pdbqt.gz.tar/' /tmp/input.txt
real 0m0.105s
user 0m0.088s
sys 0m0.016s
time (grep -v CDGA_00004.pdbqt.gz.tar /tmp/input.txt > /tmp/input.tmp; mv /tmp/input.tmp /tmp/input.txt )
real 0m0.046s
user 0m0.014s
sys 0m0.019s
Vous pouvez également utiliser ceci:
grep -v 'pattern' filename
Ici -v
, seuls les motifs seront imprimés (ce qui signifie une correspondance inversée).
perl -i -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3
La première commande modifie le (s) fichier (s) en place (-i).
La deuxième commande fait la même chose mais conserve une copie ou une sauvegarde du ou des fichiers d'origine en ajoutant .bk aux noms de fichiers (.bk peut être changé en n'importe quoi).
Juste au cas où quelqu'un voudrait le faire pour des correspondances exactes de chaînes, vous pouvez utiliser le -w
drapeau dans grep - w pour tout. C'est-à-dire, par exemple, si vous souhaitez supprimer les lignes qui ont le numéro 11, mais conservez les lignes avec le numéro 111:
-bash-4.1$ head file
1
11
111
-bash-4.1$ grep -v "11" file
1
-bash-4.1$ grep -w -v "11" file
1
111
Il fonctionne également avec le -f
drapeau si vous souhaitez exclure plusieurs modèles exacts à la fois. Si "liste noire" est un fichier avec plusieurs modèles sur chaque ligne que vous souhaitez supprimer du "fichier":
grep -w -v -f blacklist file
-w, --word-regexp Select only those lines containing matches that form whole words.
vs-x, --line-regexp Select only those matches that exactly match the whole line. For a regular expression pattern, this is like parenthesizing the pattern and then surrounding it with ^ and $.
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
pour afficher le texte traité dans la console
cat filename | sed '/text to remove/d'
enregistrer le texte traité dans un fichier
cat filename | sed '/text to remove/d' > newfile
pour ajouter des informations sur le texte traité à un fichier existant
cat filename | sed '/text to remove/d' >> newfile
pour traiter le texte déjà traité, dans ce cas, supprimez plus de lignes de ce qui a été supprimé
cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more
le | more
texte s'affichera en morceaux d'une page à la fois.
Vous pouvez utiliser le bon vieux ed
pour modifier un fichier d'une manière similaire à la réponse qui utilise ex
. La grande différence dans ce cas est qu'elle ed
prend ses commandes via une entrée standard, et non pas comme des arguments de ligne de commande comme ex
can. Lorsque vous l'utilisez dans un script, la manière habituelle de l'adapter est d'utiliser printf
pour lui rediriger des commandes:
printf "%s\n" "g/pattern/d" w | ed -s filename
ou avec un hérédoc:
ed -s filename <<EOF
g/pattern/d
w
EOF