Ja jestem przy użyciu vim (args i argdo) ilekroć muszę „potwierdzenie”, ale zastanawiałem się, czy nie było „” prostszy sposób
YuVI
1
Jest to sprzeczne z podstawowym celem sed - zautomatyzowania edycji w strumieniu.
teppic
@teppic nie jest tak naprawdę, ponieważ nadal musisz znaleźć instancje w plikach tekstowych, które sed może dla Ciebie zrobić. Myślę, że pytanie ma sens, na wypadek, gdybyś dodał niewłaściwe pliki do listy i chciał zobaczyć, który plik edytujesz
Kolob Canyon
Odpowiedzi:
37
Wykonanie tego sedprawdopodobnie nie byłoby możliwe, ponieważ jest to nieinteraktywny edytor strumieni. Owijanie sedskryptu 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 findkomendy, które robią to samo, ale dla wszystkich plików o określonej nazwie gdzieś w lub w jakimś top-dirkatalogu,
find top-dir -type f -name 'file*.txt' \
-exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;
Lub przy użyciu oryginalnych pętli powłoki i findwprowadzeniu 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
wymagałoby to grepzakończenia działania jeszcze przed rozpoczęciem pierwszej iteracji pętli, która jest nieelegancka , i
zwrócone nazwy ścieżek grepzostaną 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).
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.
Odpowiedzi:
Wykonanie tego
sed
prawdopodobnie nie byłoby możliwe, ponieważ jest to nieinteraktywny edytor strumieni. Owijaniesed
skryptu wymagałoby o wiele za dużo myślenia. Łatwiej jest to zrobić za pomocąvim
: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:
Lub, jeśli najpierw chcesz się upewnić, że plik naprawdę zawiera linię, która pasuje do podanego wzorca, przed wykonaniem podstawienia,
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,Lub przy użyciu oryginalnych pętli powłoki i
find
wprowadzeniu do nich ścieżek kanału:Ty, w każdym razie nie chcą zrobić coś takiego
for filename in $( grep -rl ... )
odgrep
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:
źródło
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:
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ń.źródło
sed
.vim
, więc ta odpowiedź ma zastosowanie; jednak wyraźnie vim i sed mają różne umiejętnościMoż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 ):źródło
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.źródło