
Tengo el requisito en mi proyecto de reemplazar algún texto existente en un archivo comofoo
con algún otro texto comofooofoo
:
abc.txt
name
foo
foo1
Entonces lo intenté:
sed -i "s/foo/fooofoo/g" abc.txt
Sin embargo me sale este error:
sed: opción ilegal -
i
Encontré en el manual que tengo que usar:
sed -i\ "s/foo/fooofoo/g" abc.txt
Sin embargo, esto tampoco funciona.
Encontré alternativas en perl
y también, pero agradecería mucho awk
una solución en Solaris .sed
Estoy usando esta versión de bash:
GNU bash, versión 3.2.57(1) (sparc-sun-solaris2.10)
Respuesta1
Usared
. Está disponible en la mayoría de las plataformas y puede editar sus archivos en el lugar.
Dado que sed
se basa en ed
la sintaxis para reemplazar patrones es similar:
ed -s infile <<\IN
,s/old/new/g
w
q
IN
Respuesta2
Si no puede instalar GNU sed, utilice:
sed "s/foo/fooofoo/g" abc.txt >abc.tmp && mv abc.tmp abc.txt
Esto usaredirecciónpara enviar la salida de sed a un archivo temporal. Si sed se completa correctamente, se sobrescribe abc.txt
con el archivo temporal.
Como se puede ver en el código fuente de GNU sed, esto es exactamente lo que sed -i
hace. Entonces, esto es casi tan eficiente como sed -i
.
Si existe la posibilidad de que abc.tmp
ya exista, es posible que desee utilizar mktemp
una utilidad similar para generar el nombre único para el temporal.
Respuesta3
Si quieres el equivalente a sed -i.bak
, es bastante simple.
Considere este script para GNU sed:
#!/bin/sh
# Create an input file to demonstrate
trap 'rm -r "$dir"' EXIT
dir=$(mktemp -d)
grep -v '[[:upper:][:punct:]]' /usr/share/dict/words | head >"$dir/foo"
# sed program - removes 'aardvark' and 'aardvarks'
script='/aard/d'
##########
# What we want to do
sed -i.bak -e "$script" "$dir"
##########
# Prove that it worked
ls "$dir"
cat "$dir/foo"
Simplemente podemos reemplazar la línea marcada con
cp "$dir/foo" "$dir/foo.bak" && sed -e "$script" "$dir/foo.bak" >"$dir/foo"
Esto mueve el archivo existente para que sea una copia de seguridad y escribe un archivo nuevo.
Si queremos el equivalente de
sed -i -e "$script" "$dir" # no backup
entonces es un poco más complejo. Podemos abrir el archivo para leerlo como entrada estándar, luego desvincularlo, antes de dirigir la salida de sed para reemplazarlo:
( cp "$dir/foo" "$dir/foo.bak"; exec <"$dir/foo.bak"; rm "$dir/foo.bak"; exec sed -e "$script" >"$dir/foo" )
Hacemos esto en un sub-shell, para que nuestra entrada estándar original todavía esté disponible después de esto. Es posible cambiar las entradas y volver a cambiar sin una subcapa, pero de esta manera me parece más clara.
Tenga en cuenta que tenemos cuidado de copiar primero, en lugar de crear un foo
archivo nuevo; esto es importante si el archivo se conoce por más de un nombre (es decir, tiene enlaces físicos) y desea asegurarse de no romper los enlaces. .
Respuesta4
Usando sed
y novisiblearchivo temporal:
Puedes evitar crear un separadovisible"archivo temporal":
exec 3<abc.txt
rm abc.txt
sed 's/foo/fooofoo/' <&3 >abc.txt
exec 3<&-
Explicación
Los sistemas tipo Unix en realidad no eliminan el contenido del archivo del disco hasta que seambosdesvinculado en el sistema de archivos,yno abierto en ningún proceso. Por lo tanto, puede exec 3<
abrir el archivo en el shell para leer el descriptor de archivo 3, rm
el archivo (que lo desvincula del sistema de archivos) y luego llamar sed
con el descriptor de archivo 3 utilizado como entrada.
Tenga en cuenta que esto esmuydiferente a esto:
# Does not work.
sed 's/foo/fooofoo/' <abc.txt >abc.txt
La diferencia es que cuando lo hace con un solo comando, el shell simplemente abre el mismo archivo para lectura y escritura con la opción de truncar el archivo; como sigue siendo el mismo archivo, pierde el contenido. Pero si lo abre para leer, rm
luego abre el mismo nombre de ruta para escribir, en realidad está creando un nuevo archivo con el mismo nombre de ruta (pero en un nuevo inodo y ubicación de disco, ya que el original todavía está abierto): entonces Los contenidos aún están disponibles.
Luego, una vez que haya terminado, puede cerrar el descriptor de archivo que abrió anteriormente (eso es lo que exec 3<&-
hace la sintaxis especial), lo que libera el archivo original para que el sistema operativo pueda eliminar (marcar como no utilizado) su espacio en disco.
Advertencias
Hay algunas cosas a tener en cuenta acerca de esta solución:
Sólo puedes revisar el contenido una vez; no hayportátilmanera para que un shell "busque" nuevamente en el descriptor de archivo, por lo que una vez que un programa lee parte del contenido, otros programas solo verán el resto del archivo. Y
sed
leerá el archivo completo.Existe una pequeña posibilidad de que su archivo original se pierda si su shell/script/sed se elimina antes de finalizar.