bash - linea - sed reemplazar/
Buscar y reemplazar dentro de un archivo de texto desde un comando Bash (14)
Bash, como otros shells, es solo una herramienta para coordinar otros comandos. Por lo general, trataría de usar los comandos estándar de UNIX, pero por supuesto puede usar Bash para invocar cualquier cosa, incluidos sus propios programas compilados, otros scripts de shell, scripts de Python y Perl, etc.
En este caso, hay un par de maneras de hacerlo.
Si desea leer un archivo y escribirlo en otro archivo, haciendo una búsqueda / reemplazo a medida que avanza, use sed:
sed ''s/abc/XYZ/g'' <infile >outfile
Si desea editar el archivo en su lugar (como si abriera el archivo en un editor, edítelo y luego guárdelo) proporcione instrucciones al editor de línea ''ex''
echo "%s/abc/XYZ/g
w
q
" | ex file
Ex es como vi sin el modo de pantalla completa. Puedes darle los mismos comandos que darías en el indicador '':'' de vi.
¿Cuál es la forma más sencilla de buscar y reemplazar una cadena de entrada dada, digamos abc
, y reemplazarla con otra cadena, digamos XYZ
en el archivo /tmp/file.txt
?
Estoy escribiendo una aplicación y usando IronPython para ejecutar comandos a través de SSH, pero no conozco bien Unix y no sé qué buscar.
He oído que Bash, además de ser una interfaz de línea de comandos, puede ser un lenguaje de scripting muy poderoso. Entonces, si esto es cierto, asumo que puedes realizar acciones como estas.
¿Puedo hacerlo con bash, y cuál es el script más simple (una línea) para lograr mi objetivo?
Encontré este hilo entre otros y estoy de acuerdo en que contiene las respuestas más completas, así que también agrego el mío:
1) sed y ed son muy útiles ... a mano !!! Mira este código de @Johnny:
sed -i -e ''s/abc/XYZ/g'' /tmp/file.txt
2) cuando mi restricción es usarla por un script de shell, no se puede usar ninguna variable dentro de abc o XYZ! This parece estar de acuerdo con lo que entiendo al menos. Entonces, no puedo usar:
x=''abc''
y=''XYZ''
sed -i -e ''s/$x/$y/g'' /tmp/file.txt
#or,
sed -i -e "s/$x/$y/g" /tmp/file.txt
¿pero que podemos hacer? Como, @Johnny dijo usar un ''mientras lee ...'' pero, desafortunadamente, ese no es el final de la historia. Lo siguiente funcionó bien conmigo:
#edit user''s virtual domain
result=
#if nullglob is set then, unset it temporarily
is_nullglob=$( shopt -s | egrep -i ''*nullglob'' )
if [[ is_nullglob ]]; then
shopt -u nullglob
fi
while IFS= read -r line; do
line="${line//''<servername>''/$server}"
line="${line//''<serveralias>''/$alias}"
line="${line//''<user>''/$user}"
line="${line//''<group>''/$group}"
result="$result""$line"''/n''
done < $tmp
echo -e $result > $tmp
#if nullglob was set then, re-enable it
if [[ is_nullglob ]]; then
shopt -s nullglob
fi
#move user''s virtual domain to Apache 2 domain directory
......
3) Como se puede ver si nullglob está configurado entonces, se comporta de manera extraña cuando hay una cadena que contiene un * como en
<VirtualHost *:80>
ServerName www.example.com
que se convierte
<VirtualHost ServerName www.example.com
¡no hay soporte de ángulo final y Apache2 ni siquiera puede cargar!
4) Este tipo de análisis debe ser más lento que la búsqueda y el reemplazo de un solo golpe, pero, como ya ha visto, hay 4 variables para 4 patrones de búsqueda diferentes que funcionan en un solo ciclo de análisis.
La solución más adecuada que puedo imaginar con los supuestos dados del problema.
Esta es una publicación antigua, pero para cualquiera que quiera usar variables como @centurian dijo que las comillas simples significan que no se expandirá nada.
Una forma sencilla de obtener variables es hacer concatenación de cadenas, ya que esto se realiza mediante yuxtaposición en bash, lo siguiente debería funcionar:
sed -i -e ''s/''"$var1"''/''"$var2"''/g'' /tmp/file.txt
La forma más fácil es usar sed (o perl):
sed -i -e ''s/abc/XYZ/g'' /tmp/file.txt
Lo que invocará a sed para hacer una edición in situ debido a la opción -i
. Esto se puede llamar desde bash.
Si realmente quieres usar solo bash, entonces lo siguiente puede funcionar:
while read a ; do echo ${a//abc/XYZ} ; done < /tmp/file.txt > /tmp/file.txt.t ; mv /tmp/file.txt{.t,}
Esto recorre cada línea, realiza una sustitución y se escribe en un archivo temporal (no se quiere bloquear la entrada). El movimiento al final solo se mueve temporalmente al nombre original.
La manipulación de archivos normalmente no se realiza mediante Bash, sino mediante programas invocados por Bash, por ejemplo:
> perl -pi -e ''s/abc/XYZ/g'' /tmp/file.txt
La bandera -i
le dice que haga un reemplazo en el lugar.
Consulte man perlrun
para obtener más detalles, incluido cómo realizar una copia de seguridad del archivo original.
Me sorprendió porque me tropecé con esto ...
Hay un comando "reemplazar" que viene con el paquete "mysql-server" , así que si lo ha instalado, pruébelo:
# replace string abc to XYZ in files
replace "abc" "XYZ" -- file.txt file2.txt file3.txt
# or pipe an echo to replace
echo "abcdef" |replace "abc" "XYZ"
Ver hombre reemplazar para más sobre esto ...
Para editar texto en el archivo de forma no interactiva, necesita un editor de texto en el lugar como vim.
Aquí hay un ejemplo simple de cómo usarlo desde la línea de comando:
vim -esnc ''%s/foo/bar/g|:wq'' file.txt
Esto es equivalente a la respuesta @slim del ex editor, que es básicamente lo mismo.
Aquí hay algunos ejemplos prácticos.
Reemplazando texto foo
con bar
en el archivo:
ex -s +%s/foo/bar/ge -cwq file.txt
Eliminar espacios en blanco finales para varios archivos:
ex +''bufdo!%s//s/+$//e'' -cxa *.txt
Ver también:
Puedes usar el comando rpl. Por ejemplo, desea cambiar el nombre de dominio en todo el proyecto de PHP.
rpl -ivRpd -x''.php'' ''old.domain.name'' ''new.domain.name'' ./path_to_your_project_folder/
Esto no está claro por la causa, pero es muy rápido y útil. :)
Puedes usar python dentro del script bash también. No tuve mucho éxito con algunas de las mejores respuestas aquí, y encontré que esto funciona sin la necesidad de bucles:
#!/bin/bash
python
filetosearch = ''/home/ubuntu/ip_table.txt''
texttoreplace = ''tcp443''
texttoinsert = ''udp1194''
s = open(filetosearch).read()
s = s.replace(texttoreplace, texttoinsert)
f = open(filetosearch, ''w'')
f.write(s)
f.close()
quit()
Puedes usar sed
sed -i ''s/abc/XYZ/gi'' /tmp/file.txt
Use i para ignorar el caso si no está seguro de que el texto a buscar sea abc o ABC o AbC, ...
Puede usar find y sed si no tiene ahora su nombre de archivo:
find ./ -type f -exec sed -i ''s/abc/XYZ/gi'' {} /;
Buscar y reemplazar en todos los archivos de python:
find ./ -iname "*.py" -type f -exec sed -i ''s/abc/XYZ/gi'' {} /;
Si el archivo en el que está trabajando no es tan grande, y almacenarlo temporalmente en una variable no es un problema, entonces puede usar la sustitución de cadenas Bash en todo el archivo a la vez, no hay necesidad de revisar línea por línea:
file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt
Todo el contenido del archivo se tratará como una cadena larga, incluidos los saltos de línea.
XYZ puede ser una variable, por ejemplo, $replacement
, y una de las ventajas de no usar sed aquí es que no debe preocuparse de que la cadena de búsqueda o reemplazo contenga el carácter delimitador del patrón sed (generalmente, pero no necesariamente, /). Una desventaja es no poder usar expresiones regulares o cualquiera de las operaciones más sofisticadas de sed.
También puede usar el comando ed para realizar búsquedas en el archivo y reemplazar:
# delete all lines matching foobar
ed -s test.txt <<< $''g/foobar/d/nw''
Ver más en el sitio de bash-hackers
Tenga cuidado si reemplaza las URL con el carácter "/".
Un ejemplo de cómo hacerlo:
sed -i "s%http://domain.com%http://www.domain.com/folder/%g" "test.txt"
Extraído de: http://www.sysadmit.com/2015/07/linux-reemplazar-texto-en-archivos-con-sed.html
encuentra ./ -type f -name "archivo * .txt" | xargs sed -i -e ''s / abc / xyz / g''