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".

Macht sed das überhaupt?

Yuvi
quelle
3
Es wäre technisch möglich, aber eher eine intellektuelle Übung als ein nützliches Unterfangen. Siehe So ersetzen Sie Text in einer großen Ordnerhierarchie das hat Vim und Perl-Lösungen.
Gilles 'SO- hör auf böse zu sein'
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' {} \;
find top-dir -type f -name 'file*.txt' \
    -exec grep -q 'PATTERN' {} \; \
    -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

  1. Es würde erfordern, dass die grepAusführung beendet wird, bevor die erste Iteration der Schleife gestartet wird , die nicht relevant ist
  2. 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).

Verbunden:

Kusalananda
quelle
2
Dies hat den Vorteil, seddass mehrere Dateien bearbeitet werden können, z. B. sed -i 's/old/new/g' /path/to/*.txtoder ähnliches.
user1717828
10
for i in $(grep -rl "old"); do vim -c "%s/old/new/gc" -c "wq" "$i"; done
tcpaiva
@tecepe, bitte konvertiere es in eine Antwort, Danke.
Nishant
1
@Nishant Dies ist eine fragile Antwort, da jede Datei, deren Name oder Pfad Leerzeichen enthält, disqualifiziert wird.
Kusalananda
7

Sie erhalten dies, indem Sie Folgendes tun:

:%s/OLD_TEXT/NEW_TEXT/gc

Insbesondere das Hinzufügen cnach dem dritten Trennzeichen.

Beachten Sie, dass die Option 'c' nur in Vim funktioniert. Sie können es nicht über seddie Befehlszeile verwenden.

Kevin M
quelle
4
Zur Verdeutlichung: Dies funktioniert nur in Vim, nicht in der regulären Befehlszeile sed.
Brendan
Das OP ist mit einem Tag versehen vim, sodass diese Antwort zutreffend ist. Es ist jedoch klar, dass Vim und Sed unterschiedliche Fähigkeiten haben
ILMostro_7
-1
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.

LyXTeX
quelle