Yo estoy usando vim (args y argdo) cada vez que necesito 'confirmación', pero me preguntaba si había una manera 'simple'
Yuvi
1
Va en contra del propósito básico de sed: automatizar la edición en una secuencia.
teppic
@teppic no es realmente porque todavía tendrías que buscar las instancias en archivos de texto, que sed puede hacer por ti. Creo que la pregunta tiene sentido, en caso de que haya agregado los archivos incorrectos a una lista y quiera ver qué archivo estaba editando
Kolob Canyon
Respuestas:
37
Hacerlo con sedprobablemente no sería posible ya que es un editor de flujo no interactivo. Ajustar sedun guión requeriría pensar demasiado. Es más fácil simplemente hacerlo con vim:
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' file.in
Como se mencionó en los comentarios a continuación, así es como se usaría en varios archivos que coinciden con un patrón de globalización de nombre de archivo en particular en el directorio actual:
for fname in file*.txt; do
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
O, si primero desea asegurarse de que el archivo realmente contenga una línea que coincida primero con el patrón dado, antes de realizar la sustitución,
for fname in file*.txt; do
grep -q 'PATTERN' "$fname" &&
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Los dos bucles de shell anteriores se modificaron en findcomandos que hacen lo mismo pero para todos los archivos con un nombre particular en algún lugar o debajo de algún top-dirdirectorio,
find top-dir -type f -name 'file*.txt' \
-exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;
O bien, utilizando los bucles de shell originales y findintroduciendo nombres de ruta en ellos:
find top-dir -type f -name 'file*.txt' -exec sh -c '
for pathname do
vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
done' sh {} +
find top-dir -type f -name 'file*.txt' -exec sh -c '
for pathname do
grep -q "PATTERN" "$pathname" &&
vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
done' sh {} +
En cualquier caso, no quieres hacer algo así for filename in $( grep -rl ... )desde
requeriría que greptermine de ejecutarse incluso antes de comenzar la primera iteración del bucle, que es poco elegante , y
los nombres de ruta devueltos por grepse dividirían en palabras en espacios en blanco, y estas palabras sufrirían un bloqueo de nombre de archivo (esto descalifica nombres de ruta que contienen espacios y caracteres especiales).
searchandreplace () {
if [ -z $2 ] ; then
realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
else
realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
exp=$(realpath * | xargs grep -ins --directories=skip --color=never "$1" | cut -d':' -f1,2 | awk -F':' '{print $2 $1}' | sed -E "s|^[0-9]+|sed -i \'&s/|; s|//|/"$1"/"$2"/g\' /|")
IFS=$'\n'
for d in $exp
do
read -p "Exec $(echo -e -n "\033[1;31m$d\033[0m")? " -e REP
if [ "$REP" = y ]; then
echo `bash -c $d`;
fi
done
fi
}
Si alimenta esto con un solo argumento, searchandreplace "AAA"solo busca esa cadena en el directorio actual, pero si la alimenta con argumentos dobles, searchandreplace AAA BBBademás del anterior, también le pide que reemplace la primera con la segunda línea por línea "para cada línea.
Respuestas:
Hacerlo con
sed
probablemente no sería posible ya que es un editor de flujo no interactivo. Ajustarsed
un guión requeriría pensar demasiado. Es más fácil simplemente hacerlo convim
:Como se mencionó en los comentarios a continuación, así es como se usaría en varios archivos que coinciden con un patrón de globalización de nombre de archivo en particular en el directorio actual:
O, si primero desea asegurarse de que el archivo realmente contenga una línea que coincida primero con el patrón dado, antes de realizar la sustitución,
Los dos bucles de shell anteriores se modificaron en
find
comandos que hacen lo mismo pero para todos los archivos con un nombre particular en algún lugar o debajo de algúntop-dir
directorio,O bien, utilizando los bucles de shell originales y
find
introduciendo nombres de ruta en ellos:En cualquier caso, no quieres hacer algo así
for filename in $( grep -rl ... )
desdegrep
termine de ejecutarse incluso antes de comenzar la primera iteración del bucle, que es poco elegante , ygrep
se dividirían en palabras en espacios en blanco, y estas palabras sufrirían un bloqueo de nombre de archivo (esto descalifica nombres de ruta que contienen espacios y caracteres especiales).Relacionado:
fuente
sed
es que puede operar en múltiples archivos, por ejemplo,sed -i 's/old/new/g' /path/to/*.txt
o algo similar.for i in $(grep -rl "old"); do vim -c "%s/old/new/gc" -c "wq" "$i"; done
Puede obtener esto haciendo lo siguiente:
Específicamente, agregando
c
después del tercer delimitador.Tenga en cuenta que la opción 'c' solo funciona en Vim; no podrás usarlo
sed
en la línea de comando.fuente
sed
.vim
, por lo que esta respuesta es aplicable; sin embargo, claramente vim y sed tienen diferentes habilidadesPuede dejar que
sed
haga lo suyo en el archivo y luego guardar el resultado en un archivo temporal que luego puede parchear interactivamente en el archivo original utilizandosdiff
(consulte http://www.gnu.org/software/diffutils/manual/diffutils.html # Invocando-sdiff ):fuente
Si alimenta esto con un solo argumento,
searchandreplace "AAA"
solo busca esa cadena en el directorio actual, pero si la alimenta con argumentos dobles,searchandreplace AAA BBB
además del anterior, también le pide que reemplace la primera con la segunda línea por línea "para cada línea.fuente