¿Hay alguna manera de hacer que sed me solicite confirmación antes de cada reemplazo? Algo similar a 'c' cuando se usa reemplazar dentro de vim.
¿Sed hace esto en absoluto?
¿Hay alguna manera de hacer que sed me solicite confirmación antes de cada reemplazo? Algo similar a 'c' cuando se usa reemplazar dentro de vim.
¿Sed hace esto en absoluto?
Respuestas:
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' {} \;
find top-dir -type f -name 'file*.txt' \
-exec grep -q 'PATTERN' {} \; \
-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
greptermine de ejecutarse incluso antes de comenzar la primera iteración del bucle, que es poco elegante , ygrepse 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:
sedes que puede operar en múltiples archivos, por ejemplo, sed -i 's/old/new/g' /path/to/*.txto 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:
:%s/OLD_TEXT/NEW_TEXT/gc
Específicamente, agregando cdespués del tercer delimitador.
Tenga en cuenta que la opción 'c' solo funciona en Vim; no podrás usarlo seden la línea de comando.
sed.
vim, por lo que esta respuesta es aplicable; sin embargo, claramente vim y sed tienen diferentes habilidades
Puede dejar que sedhaga lo suyo en el archivo y luego guardar el resultado en un archivo temporal que luego puede parchear interactivamente en el archivo original utilizando sdiff(consulte http://www.gnu.org/software/diffutils/manual/diffutils.html # Invocando-sdiff ):
sed -r 's/something/something_else/g' my_file > tmp_file
sdiff -o my_file -s -d my_file tmp_file
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.