El siguiente comando está cambiando correctamente el contenido de 2 archivos.
sed -i 's/abc/xyz/g' xaa1 xab1
Pero lo que tengo que hacer es cambiar dinámicamente varios de estos archivos y no sé los nombres de los archivos. Quiero escribir un comando que lea todos los archivos del directorio actual comenzando xa*
y que sed
debería cambiar el contenido del archivo.
sed -i 's/abc/xyz/g' xa*
?Respuestas:
Mejor todavía:
porque nadie sabe cuántos archivos hay y es fácil romper los límites de la línea de comandos.
Esto es lo que sucede cuando hay demasiados archivos:
fuente
for
comando. Para protegerte de eso, deberías usarlofind ... | xargs ...
for
paraecho
ogrep
?"$i"
lugar de$i
evitar la división de palabras en nombres de archivos con espacios. De lo contrario, esto es muy agradable.for
es parte de la sintaxis del lenguaje, no solo una versión incorporada. Parased -i 's/old/new' *
, la expansión de*
TODO debe pasar como un arglista para sed, y estoy bastante seguro de que esto tiene que suceder antes de que elsed
proceso pueda comenzar. Usando elfor
bucle, el arglista completo (la expansión de*
) nunca se pasa como un comando, solo se almacena en la memoria del shell y se repite. Sin embargo, no tengo ninguna referencia para esto, solo parece probable que esa sea la diferencia. (Me encantaría saber de alguien más conocedor ...)Me sorprende que nadie haya mencionado el argumento -exec para buscar, que está destinado a este tipo de casos de uso, aunque comenzará un proceso para cada nombre de archivo coincidente:
Alternativamente, uno podría usar xargs, que invocará menos procesos:
O más simplemente use la
+
variante exec en lugar de;
en find para permitir que find proporcione más de un archivo por llamada de subproceso:fuente
find ./ -type f -name 'xa*' -exec sed -i '' 's/asd/dsg/g' {} \;
esa es la ubicación del comando find./
y un par de comillas simples-i
para OSX../
es igual.
y-i
solo tiene el parámetro backupsuffix.-exec
opción de buscar junto con{} +
es suficiente para resolver el problema como se indicó, y debería estar bien para la mayoría de los requisitos. Peroxargs
es una mejor opción en general porque también permite el procesamiento paralelo con la-p
opción. Cuando su expansión global es lo suficientemente grande como para desbordar la longitud de su línea de comando, es probable que también se beneficie de una aceleración en una ejecución secuencial.Podrías usar grep y sed juntos. Esto le permite buscar subdirectorios de forma recursiva.
fuente
grep -v
para evitar las carpetas gitgrep -rl <old> . | grep -v \.git | xargs sed -i 's/<old>/<new>/g'
Esos comandos no funcionarán en el valor predeterminado
sed
que viene con Mac OS X.De
man 1 sed
:Intentó
y
Ambos funcionan bien.
fuente
@PaulR publicó esto como un comentario, pero la gente debería verlo como una respuesta (y esta respuesta funciona mejor para mis necesidades):
Esto funcionará para una cantidad moderada de archivos, probablemente del orden de decenas, pero probablemente no del orden de millones .
fuente
sed -i 's|auth-user-pass nordvpn.txt|auth-user-pass /etc/openvpn/nordvpn.txt|g' *.ovpn
.Otra forma más versátil es usar
find
:fuente
Estoy usando
find
para una tarea similar. Es bastante simple: tienes que pasarlo como argumento parased
esto:sed -i 's/EXPRESSION/REPLACEMENT/g' `find -name "FILE.REGEX"`
De esta manera, no tiene que escribir bucles complejos, y es fácil ver qué archivos va a cambiar, solo ejecute
find
antes de ejecutarsed
.fuente
puedes hacer
el texto ' xxxx ' busca y lo reemplazará con ' aaaa '
fuente
Si puede ejecutar un script, esto es lo que hice para una situación similar:
Usando un diccionario / hashMap (matriz asociativa) y variables para el
sed
comando, podemos recorrer la matriz para reemplazar varias cadenas. La inclusión de un comodín en elname_pattern
permitirá reemplazar en el lugar en los archivos con un patrón (esto podría ser algo asíname_pattern='File*.txt'
) en un directorio específico (source_dir
). Todos los cambios están escritoslogfile
en eldestin_dir
Primero, se declara la matriz de pares, cada par es una cadena de reemplazo, luego
WHAT1
se reemplazará porFOR1
yOTHER_string_to replace
se reemplazará porstring replaced
en el archivoFile.txt
. En el bucle se lee la matriz, el primer miembro del par se recupera comoreplace_what=$i
y el segundo comoreplace_for=$j
. Elfind
comando busca en el directorio el nombre del archivo (que puede contener un comodín) y elsed -i
comando reemplaza en el mismo archivo (s) lo que se definió previamente. Finalmente agregué ungrep
archivo redirigido al archivo de registro para registrar los cambios realizados en los archivos.Esto funcionó para mí
GNU Bash 4.3
sed 4.2.2
y se basó en la respuesta de VasyaNovikov para Loop over tuples in bash .fuente