Existe uma maneira de fazer com que o sed me peça uma confirmação antes de cada substituição? Algo semelhante ao 'c' ao usar substituir dentro do vim.
O sed faz isso?
Existe uma maneira de fazer com que o sed me peça uma confirmação antes de cada substituição? Algo semelhante ao 'c' ao usar substituir dentro do vim.
O sed faz isso?
Respostas:
Fazê-lo com sedprovavelmente não seria possível, pois ele é um editor de fluxo não-interativo. A quebra sedde um script exigiria muito pensamento. É mais fácil fazer isso com vim:
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' file.in
Como foi mencionado nos comentários abaixo, veja como isso seria usado em vários arquivos que correspondam a um padrão de globbing de nome de arquivo específico no diretório atual:
for fname in file*.txt; do
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Ou, se você deseja primeiro garantir que o arquivo realmente contenha uma linha que corresponda ao padrão especificado primeiro, antes de executar a substituição,
for fname in file*.txt; do
grep -q 'PATTERN' "$fname" &&
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Os dois loops de shell acima modificados em findcomandos que fazem as mesmas coisas, mas para todos os arquivos com um nome específico em algum lugar ou sob algum top-dirdiretório,
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' {} \;
Ou, usando os loops de shell originais e tendo findnomes de caminho neles:
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 {} +
De qualquer forma, você não quer fazer algo como for filename in $( grep -rl ... )desde
grepexecução fosse executada antes mesmo de iniciar a primeira iteração do loop, que é deselegante , egrepseriam divididos em palavras em espaços em branco, e essas palavras sofreriam um globbing de nome de arquivo (isso desqualifica nomes de caminho que contêm espaços e caracteres especiais).Palavras-chave:
sedé que ele pode operar em vários arquivos, por exemplo, sed -i 's/old/new/g' /path/to/*.txtou algo semelhante.
for i in $(grep -rl "old"); do vim -c "%s/old/new/gc" -c "wq" "$i"; done
Você pode obter isso fazendo o seguinte:
:%s/OLD_TEXT/NEW_TEXT/gc
Especificamente, adicionando o cdepois do terceiro delimitador.
Observe que a opção 'c' funciona apenas no Vim; você não poderá usá-lo sedna linha de comando.
sed.
vim, portanto, esta resposta é aplicável; no entanto, claramente vim e sed têm habilidades diferentes
Você pode deixar o sedseu trabalho no arquivo e salvar o resultado em um arquivo temporário, que pode ser conectado interativamente ao arquivo original usando sdiff(consulte http://www.gnu.org/software/diffutils/manual/diffutils.html # Invoking-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
}
Se você alimenta isso com argumento único - searchandreplace "AAA"- ele procura apenas essa sequência no diretório atual, mas se você alimenta com argumentos duplos - searchandreplace AAA BBB- além do acima, ele também solicita que você substitua a primeira pela segunda "linha por linha "para cada linha.