Czy istnieje sposób, aby sed pytał mnie o potwierdzenie przed każdą wymianą? Coś podobnego do „c” przy użyciu polecenia replace inside vim.
Czy sed w ogóle to robi?
Czy istnieje sposób, aby sed pytał mnie o potwierdzenie przed każdą wymianą? Coś podobnego do „c” przy użyciu polecenia replace inside vim.
Czy sed w ogóle to robi?
Odpowiedzi:
Wykonanie tego sed
prawdopodobnie nie byłoby możliwe, ponieważ jest to nieinteraktywny edytor strumieni. Owijanie sed
skryptu wymagałoby o wiele za dużo myślenia. Łatwiej jest to zrobić za pomocą vim
:
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' file.in
Ponieważ zostało to wspomniane w komentarzach poniżej, oto jak zostanie to zastosowane w wielu plikach pasujących do określonego wzorca globowania nazw plików w bieżącym katalogu:
for fname in file*.txt; do
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Lub, jeśli najpierw chcesz się upewnić, że plik naprawdę zawiera linię, która pasuje do podanego wzorca, przed wykonaniem podstawienia,
for fname in file*.txt; do
grep -q 'PATTERN' "$fname" &&
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Dwie powyższe pętle powłoki zostały zmodyfikowane w find
komendy, które robią to samo, ale dla wszystkich plików o określonej nazwie gdzieś w lub w jakimś top-dir
katalogu,
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' {} \;
Lub przy użyciu oryginalnych pętli powłoki i find
wprowadzeniu do nich ścieżek kanału:
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 {} +
Ty, w każdym razie nie chcą zrobić coś takiego for filename in $( grep -rl ... )
od
grep
zakończenia działania jeszcze przed rozpoczęciem pierwszej iteracji pętli, która jest nieelegancka , igrep
zostaną podzielone na słowa na białych spacjach, a słowa te zostaną poddane globalizacji nazw plików (dyskwalifikuje ścieżki zawierające spacje i znaki specjalne).Związane z:
sed
jest to, że może działać na wielu plikach, np. sed -i 's/old/new/g' /path/to/*.txt
Lub coś podobnego.
for i in $(grep -rl "old"); do vim -c "%s/old/new/gc" -c "wq" "$i"; done
Możesz to zrobić, wykonując takie czynności:
:%s/OLD_TEXT/NEW_TEXT/gc
W szczególności dodanie c
trzeciego separatora po.
Zauważ, że opcja „c” działa tylko w Vimie; nie będziesz mógł używać go sed
w wierszu poleceń.
sed
.
vim
, więc ta odpowiedź ma zastosowanie; jednak wyraźnie vim i sed mają różne umiejętności
Możesz sed
zrobić to na pliku, a następnie zapisać wynik w pliku tymczasowym, który następnie możesz interaktywnie załatać do oryginalnego pliku za pomocą sdiff
(patrz 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
}
Jeśli podajesz to z jednym argumentem - searchandreplace "AAA"
- wyszukuje tylko ten ciąg w bieżącym katalogu, ale jeśli podajesz go z podwójnymi argumentami - searchandreplace AAA BBB
- to oprócz powyższego prosi również o zastąpienie pierwszego z drugiego wiersza „ linia ”dla każdej linii.