¿Cómo usaría sed para eliminar todas las líneas en un archivo de texto que contiene una cadena específica?
¿Cómo usaría sed para eliminar todas las líneas en un archivo de texto que contiene una cadena específica?
Respuestas:
Para eliminar la línea e imprimir la salida al estándar:
sed '/pattern to match/d' ./infile
Para modificar directamente el archivo, no funciona con BSD sed:
sed -i '/pattern to match/d' ./infile
Lo mismo, pero para BSD sed (Mac OS X y FreeBSD), no funciona con GNU sed:
sed -i '' '/pattern to match/d' ./infile
Para modificar directamente el archivo (y crear una copia de seguridad): funciona con BSD y GNU sed:
sed -i.bak '/pattern to match/d' ./infile
sed '/pattern to match/d' ./infile > ./newfile
o si desea hacer una edición en el lugar, puede agregar la -i
bandera a sed como en sed -i '/pattern to match/d' ./infile
. Tenga en cuenta que la -i
bandera requiere GNU sed y no es portátil
sed -i.backup '/pattern to match/d' ./infile
. ej. ) Eso me ayudó con las ediciones in situ.
sed
a ningún archivo que no esté controlado por la versión.
sed -i '' '/pattern/d' ./infile
.
Hay muchas otras formas de eliminar líneas con una cadena específica además de 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
Y, por supuesto sed
(imprimir el inverso es más rápido que la eliminación real):
sed -n '/pattern/!p' file
sed
ejemplo tiene un comportamiento diferente, solo greps! Debería ser algo así sed -n -i '/pattern/!p' file
.
grep -v "pattern" file > temp; mv temp file
esto podría aplicarse a algunos de los otros ejemplos dependiendo del valor de retorno.
seq -f %f 10000000 >foo.txt
. sed d: time sed -i '' '/6543210/d' foo.txt
real 0m9.294s. sed! p: time sed -i '' -n '/6543210/!p' foo.txt
real 0m13.671s. (Para archivos más pequeños, la diferencia es mayor.)
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 tarda 3 veces más en mi máquina de todos modos.
sed '/pattern/d' filename > filename2; mv filename2 filename
La forma fácil de hacerlo, con GNU sed
:
sed --in-place '/some string here/d' yourfile
-r
opción (o -E
, dependiendo de su versión). Esto permite el uso de metacaracteres de expresiones regulares +
, ?
, {...}
y (...)
.
Puede considerar usar ex
(que es un editor estándar basado en comandos de Unix):
ex +g/match/d -cwq file
dónde:
+
se ejecuta dado el comando Ex ( man ex
), igual que el -c
que se ejecuta wq
(escribir y salir)g/match/d
- Ex comando para eliminar líneas con dado match
, ver: Poder de gEl ejemplo anterior es un método compatible con POSIX para editar in situ un archivo según esta publicación en las especificaciones ex
Unix.SE y POSIX para .
La diferencia con sed
es que:
sed
es un S TREAM ED itor, no un editor de archivos. BashFAQ
A menos que disfrute de código no portable, sobrecarga de E / S y algunos otros efectos secundarios negativos. Básicamente, algunos parámetros (como in-place / -i
) son extensiones de FreeBSD no estándar y pueden no estar disponibles en otros sistemas operativos.
man ex
me da el hombre para vim
, al parecer ex
es parte de vim ... si he entendido bien que mediante la sintaxis de patrón para match
es vimregex.com que es similar pero diferente a los sabores POSIX y PCRE?
:g
es un comando compatible con POSIX con algunas pequeñas diferencias . Supongo que PCRE se basó en ello.
Estaba luchando con esto en Mac. Además, necesitaba hacerlo usando un reemplazo variable.
Entonces usé:
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 la eliminación.
Elegí el ''
de este comentario .
Lo que hay que tener en cuenta es el uso de comillas dobles en "/$pattern/d"
. La variable no funcionará cuando usemos comillas simples.
sed
requiere un parámetro después -i
, por lo que si no desea una copia de seguridad, aún debe agregar una cadena vacía:-i ''
sed -i "/$pattern/d" $file
. Gracias por su respuesta.
Hice un pequeño punto de referencia con un archivo que contiene aproximadamente 345 000 líneas. El camino con grep
parece ser alrededor de 15 veces más rápido que el sed
método en este caso.
He intentado con y sin la configuración 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 el 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
También puedes usar esto:
grep -v 'pattern' filename
Aquí -v
se imprimirá solo que no sea su patrón (eso significa invertir coincidencia).
perl -i -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3
El primer comando edita los archivos in situ (-i).
El segundo comando hace lo mismo pero mantiene una copia o una copia de seguridad de los archivos originales agregando .bk a los nombres de archivo (.bk se puede cambiar a cualquier cosa).
En caso de que alguien quiera hacerlo para coincidencias exactas de cadenas, puede usar la -w
bandera en grep - w para todo. Es decir, por ejemplo, si desea eliminar las líneas que tienen el número 11, pero mantener 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 la -f
bandera 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 del "archivo":
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
para mostrar el texto tratado en la consola
cat filename | sed '/text to remove/d'
para guardar el texto tratado en un archivo
cat filename | sed '/text to remove/d' > newfile
para agregar información de texto tratado a un archivo existente
cat filename | sed '/text to remove/d' >> newfile
para tratar el texto ya tratado, en este caso, elimine más líneas de lo que se ha eliminado
cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more
el | more
mostrará texto en fragmentos de una página a la vez.
Puede usar good old ed
para editar un archivo de manera similar a la respuesta que usa ex
. La gran diferencia en este caso es que ed
toma sus comandos a través de una entrada estándar, no como argumentos de línea de comandos como ex
puede. Cuando se usa en un script, la forma habitual de acomodar esto es usar printf
comandos de canalización:
printf "%s\n" "g/pattern/d" w | ed -s filename
o con un heredoc:
ed -s filename <<EOF
g/pattern/d
w
EOF