shell - script - Eliminar líneas en un archivo de texto que contienen una cadena específica
sed eliminar caracter (14)
¿Cómo usaría sed para eliminar todas las líneas en un archivo de texto que contiene una cadena específica?
En caso de que alguien quiera hacerlo para obtener coincidencias exactas de las cadenas, puede usar el indicador -w
en grep -w para todo. Es decir, por ejemplo, si desea eliminar las líneas que tienen el número 11, pero mantenga las líneas con el número 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
También funciona con el indicador -f
si desea excluir varios patrones exactos a la vez. Si "lista negra" es un archivo con varios patrones en cada línea que desea eliminar de "archivo":
grep -w -v -f blacklist file
Hay muchas otras formas de eliminar líneas con una cadena específica además de sed
:
AWK
awk ''!/pattern/'' file > temp && mv temp file
Ruby (1.9+)
ruby -i.bak -ne ''print if not /test/'' file
Perl
perl -ni.bak -e "print unless /pattern/" file
Shell (bash 3.2 y posteriores)
while read -r line
do
[[ ! $line =~ pattern ]] && echo "$line"
done <file > o
mv o file
GNU grep
grep -v "pattern" file > temp && mv temp file
Y, por supuesto, sed
(imprimir el inverso es más rápido que la eliminación real):
sed -n ''/pattern/!p'' file
He hecho un pequeño punto de referencia con un archivo que contiene aproximadamente 345 000 líneas. La forma con grep
parece ser alrededor de 15 veces más rápida que el método sed
en este caso.
He intentado con y sin el ajuste LC_ALL = C, no parece cambiar los tiempos significativamente. La cadena de búsqueda (CDGA_00004.pdbqt.gz.tar) está en algún lugar en medio del archivo.
Aquí están los comandos y los tiempos:
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
La forma más fácil de hacerlo, con GNU sed
:
sed --in-place ''/some string here/d'' yourfile
Para eliminar la línea e imprimir la salida a la salida estándar:
sed ''/pattern to match/d'' ./infile
Para modificar directamente el archivo:
sed -i ''/pattern to match/d'' ./infile
Para modificar directamente el archivo (y crear una copia de seguridad):
sed -i.bak ''/pattern to match/d'' ./infile
Para usuarios de Mac OS X y FreeBSD:
sed -i '''' ''/pattern/d'' ./infile
Para obtener un resultado in situ con grep
puede hacer esto:
echo "$(grep -v "pattern" filename)" >filename
Puede considerar usar ex
(que es un editor estándar basado en comandos de Unix):
ex +g/match/d -cwq file
dónde:
-
+
ejecuta el comando Ex dado (man ex
), igual que-c
que ejecutawq
(escribir y salir) -
g/match/d
- Ex comando para eliminar líneas con unamatch
dada, ver: Potencia de g
El ejemplo anterior es un método compatible con POSIX para la edición en contexto de un archivo según esta publicación en Unix.SE y POSIX especificaciones para ex
.
La diferencia con sed
es que:
sed
es un editor de S tream ED , no un editor de archivos. BashFAQ
A menos que disfrute de código no portátil, sobrecarga de E / S y algunos otros efectos secundarios negativos. Básicamente, algunos parámetros (como in-place / -i
) no son extensiones FreeBSD estándar y pueden no estar disponibles en otros sistemas operativos.
Puede usar sed para reemplazar las líneas en su lugar en un archivo. Sin embargo, parece ser mucho más lento que usar grep para el inverso en un segundo archivo y luego mover el segundo archivo sobre el original.
p.ej
sed -i ''/pattern/d'' filename
o
grep -v "pattern" filename > filename2; mv filename2 filename
El primer comando toma 3 veces más en mi máquina de todos modos.
También puedes usar esto:
grep -v ''pattern'' filename
Aquí -v
imprimirá solo otro que no sea su patrón (lo que significa invertir coincidencia).
Yo estaba luchando con esto en Mac. Además, necesitaba hacerlo usando reemplazo variable.
Así que utilicé:
sed -i '''' "/$pattern/d" $file
donde $file
es el archivo donde se necesita la eliminación y $pattern
es el patrón que debe coincidir para su eliminación.
Escogí el ''''
de este comment .
Lo que hay que tener en cuenta aquí es el uso de comillas dobles en "/$pattern/d"
. La variable no funcionará cuando usamos comillas simples.
echo -e "/thing_to_delete/ndd/033:x/n" | vim file_to_edit.txt
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
perl -i -nle''/regexp/||print'' file1 file2 file3
perl -i.bk -nle''/regexp/||print'' file1 file2 file3
El primer comando edita el (los) archivo (s) inplace (-i).
El segundo comando hace lo mismo pero mantiene una copia o copia de seguridad de los archivos originales al agregar .bk a los nombres de los archivos (.bk puede cambiarse a cualquier cosa).