Bitten Sie sed vor jedem Austausch um Bestätigung?
37
Gibt es eine Möglichkeit, sed dazu zu bringen, mich vor jedem Austausch um Bestätigung zu bitten? Ähnliches wie "c" bei Verwendung von "replace inside vim".
Ich bin mit vim (args und argdo) , wann immer ich ‚Bestätigung‘ benötigen, aber frag dich , ob es einen ‚einfacheren‘ Weg war
Yuvi
1
Es widerspricht dem grundlegenden Zweck von sed - das Bearbeiten über einen Stream zu automatisieren.
Teppic
@teppic nicht wirklich, weil du noch die Instanzen in Textdateien finden müsstest , was sed für dich tun kann. Ich denke, die Frage ist sinnvoll, nur für den Fall, dass Sie die falschen Dateien zu einer Liste hinzugefügt haben und sehen möchten, welche Datei Sie gerade bearbeiten
Kolob Canyon
Antworten:
37
Dies sedwäre wahrscheinlich nicht möglich, da es sich um einen nicht interaktiven Stream-Editor handelt. Das Einschließen sedeines Skripts würde viel zu viel Nachdenken erfordern. Es ist einfacher, es einfach mit vim:
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' file.in
Da dies in den Kommentaren weiter unten erwähnt wurde, wird dies für mehrere Dateien verwendet, die mit einem bestimmten Dateinamen-Globbing-Muster im aktuellen Verzeichnis übereinstimmen:
for fname in file*.txt; do
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Oder, wenn Sie zuerst sicherstellen möchten, dass die Datei wirklich eine Linie enthält, die zuerst mit dem angegebenen Muster übereinstimmt, bevor Sie die Ersetzung durchführen,
for fname in file*.txt; do
grep -q 'PATTERN' "$fname" &&
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Die beiden obigen Shell-Schleifen wurden in findBefehle umgewandelt, die dieselben Aktionen ausführen, jedoch für alle Dateien mit einem bestimmten Namen, die sich irgendwo in oder unter einem top-dirVerzeichnis befinden.
find top-dir -type f -name 'file*.txt' \
-exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;
Oder verwenden Sie die ursprünglichen Shell-Schleifen und geben Sie findPfadnamen ein:
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 {} +
Sie, in jedem Fall nicht wollen , etwas zu tun wie for filename in $( grep -rl ... )seit
Es würde erfordern, dass die grepAusführung beendet wird, bevor die erste Iteration der Schleife gestartet wird , die nicht relevant ist
Die von zurückgegebenen Pfadnamen grepwürden in Wörter mit Leerzeichen aufgeteilt, und diese Wörter würden einer Dateinamenverschiebung unterzogen (dies disqualifiziert Pfadnamen, die Leerzeichen und Sonderzeichen enthalten).
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
}
Wenn Sie dies mit einem einzigen Argument eingeben - searchandreplace "AAA"- sucht es nur im aktuellen Verzeichnis nach dieser Zeichenfolge, aber wenn Sie es mit doppelten Argumenten eingeben - searchandreplace AAA BBB- werden Sie zusätzlich dazu aufgefordert, die erste durch die zweite "Zeile durch" zu ersetzen line "für jede Zeile.
Antworten:
Dies
sed
wäre wahrscheinlich nicht möglich, da es sich um einen nicht interaktiven Stream-Editor handelt. Das Einschließensed
eines Skripts würde viel zu viel Nachdenken erfordern. Es ist einfacher, es einfach mitvim
:Da dies in den Kommentaren weiter unten erwähnt wurde, wird dies für mehrere Dateien verwendet, die mit einem bestimmten Dateinamen-Globbing-Muster im aktuellen Verzeichnis übereinstimmen:
Oder, wenn Sie zuerst sicherstellen möchten, dass die Datei wirklich eine Linie enthält, die zuerst mit dem angegebenen Muster übereinstimmt, bevor Sie die Ersetzung durchführen,
Die beiden obigen Shell-Schleifen wurden in
find
Befehle umgewandelt, die dieselben Aktionen ausführen, jedoch für alle Dateien mit einem bestimmten Namen, die sich irgendwo in oder unter einemtop-dir
Verzeichnis befinden.Oder verwenden Sie die ursprünglichen Shell-Schleifen und geben Sie
find
Pfadnamen ein:Sie, in jedem Fall nicht wollen , etwas zu tun wie
for filename in $( grep -rl ... )
seitgrep
Ausführung beendet wird, bevor die erste Iteration der Schleife gestartet wird , die nicht relevant istgrep
würden in Wörter mit Leerzeichen aufgeteilt, und diese Wörter würden einer Dateinamenverschiebung unterzogen (dies disqualifiziert Pfadnamen, die Leerzeichen und Sonderzeichen enthalten).Verbunden:
quelle
sed
dass mehrere Dateien bearbeitet werden können, z. B.sed -i 's/old/new/g' /path/to/*.txt
oder ähnliches.for i in $(grep -rl "old"); do vim -c "%s/old/new/gc" -c "wq" "$i"; done
Sie erhalten dies, indem Sie Folgendes tun:
Insbesondere das Hinzufügen
c
nach dem dritten Trennzeichen.Beachten Sie, dass die Option 'c' nur in Vim funktioniert. Sie können es nicht über
sed
die Befehlszeile verwenden.quelle
sed
.vim
, sodass diese Antwort zutreffend ist. Es ist jedoch klar, dass Vim und Sed unterschiedliche Fähigkeiten habenSie können
sed
die Datei bearbeiten und das Ergebnis in einer temporären Datei speichern, die Sie dann interaktiv in die Originaldatei einfügen könnensdiff
(siehe http://www.gnu.org/software/diffutils/manual/diffutils.html) # Invoking-sdiff ):quelle
Wenn Sie dies mit einem einzigen Argument eingeben -
searchandreplace "AAA"
- sucht es nur im aktuellen Verzeichnis nach dieser Zeichenfolge, aber wenn Sie es mit doppelten Argumenten eingeben -searchandreplace AAA BBB
- werden Sie zusätzlich dazu aufgefordert, die erste durch die zweite "Zeile durch" zu ersetzen line "für jede Zeile.quelle