it-swarm.com.de

Suchen und Ersetzen vom Terminal aus, jedoch mit Bestätigung

In vielen Texteditoren können Sie suchen und ersetzen und die Option erhalten, jeden gefundenen Fall zu überprüfen. Ich möchte in Ubuntu etwas Ähnliches über die Kommandozeile ausführen können. Ich weiß, dass sed die Möglichkeit bietet, Zeichenfolgen in mehreren Dateien zu suchen und zu ersetzen, aber gibt es trotzdem die Möglichkeit, jede Ersetzung vom Benutzer bestätigen zu lassen?

Im Idealfall hätte ich gerne eine Lösung, mit der ich diese "auffordernde" Suche und Ersetzung für alle Dateien in einem Verzeichnis durchführen kann.

Wie wäre es mit Vim?

vim '+%s/set/bar/gc' some_file
  • + wird verwendet, um einen Befehl auszuführen, nachdem die Datei geladen wurde.
  • % führt den Befehl über den gesamten Puffer (Datei) aus.
  • gc sind Flags für :substitute, g, um alle Ausdrücke in der Zeile zu bearbeiten, und c, um jede Ersetzung zu bestätigen.

Sie können Vim nicht daran hindern, die Datei zu öffnen, aber Sie können das Speichern und Beenden automatisieren:

vim '+bufdo %s/set/bar/gc | up' '+q' some_file another_file
  • bufdo führt den Befehl über jeden Puffer aus. Dies schließt den Teil nach | ein, sodass Änderungen an jedem Puffer gespeichert werden ( up ).
  • q wird beendet, wodurch Vim beendet wird, da wir uns jetzt im letzten Puffer befinden.
6
muru

Sie können die Kombination aus find und dem Befehl _-ok_ verwenden. Dieser Befehl ist mit dem Befehl _-exec_ identisch, fragt den Benutzer jedoch zuerst, bevor der angegebene Befehl ausgeführt wird. Wenn der Benutzer einverstanden ist, führen Sie den Befehl aus. Andernfalls geben Sie einfach false zurück.

von man find :

_-ok command ;
      Like  -exec  but ask the user first. If the user agrees, run the command. 
      Otherwise just return false. If the command is run, its standard input is 
      redirected from /dev/null.
_

Sie können den Befehl also wie folgt verwenden:

_$ find ./ -name filename -ok sed 's/foo/bar/' {} \;
< sed ... filename > ?
_

dadurch wird der Benutzer aufgefordert, wie in der zweiten Zeile oben gezeigt.

Wenn Sie y eingeben, wird der Befehl sed replacement ausgeführt und Ihr Ersatz ausgeführt. Wenn Sie n eingeben, ignoriert der Befehl _-ok_ den Befehl sed.


Wenn Sie dies "veranlasst" wollen find und replace für alle Dateien in einem Verzeichnis, verwenden Sie den Befehl wie folgt:

_$ find /path/to/directory -type f -ok sed 's/foo/bar/' {} \;
_
4
αғsнιη

Ich würde einfach ein kleines Perl-Skript schreiben:

#!/usr/bin/env Perl
use strict;
use warnings;

my $pat="$ARGV[0]";
my $replacement=$ARGV[1];
my $file="$ARGV[2]";

## Open the input file
open(my $fh, "$file");

## Read the file line by line
while (<$fh>) {
    ## If this line matches the pattern
    if (/$pat/) {
        ## Print the current line
        print STDERR "Line $. : $_";
        ## Prompt the user for an action
        print STDERR "Substitute $pat with $replacement [y,n]?\n";
        ## Read the user's answer
        my $response=<STDIN>;
        ## Remove trailing newline
        chomp($response);
        ## If the answer is y or Y, make the replacement.
        ## All other responses will be ignored. 
        if ($response eq 'Y' || $response eq 'y') {
            s/$pat/$replacement/g;
        }    
    }
    ## Print the current line. Note that this will 
    ## happen irrespective of whether a replacement occured.
    print;
}

Speichern Sie die Datei als ~/bin/replace.pl, machen Sie sie mit chmod a+x ~/bin/replace.pl ausführbar und führen Sie sie mit dem Muster aus, das als erstes Argument, das Ersetzen als zweites und den Dateinamen als drittes übereinstimmt:

replace.pl foo bar file > newfile

Um es für mehrere Dateien auszuführen, z. B. für alle *.txt -Dateien, schließen Sie es in eine Bash-Schleife ein:

for file in *txt; do 
    replace.pl foo bar "$file" > "$file".new
done

Und um die Datei "an Ort und Stelle" zu bearbeiten:

for file in *txt; do 
    tmp=$(mktemp)
    replace.pl foo bar "$file" > "$tmp" && mv "$tmp" "$file"
done
2
terdon

Sie können Murus Vorschlag, vim zu verwenden mit AFSHINs Vorschlag, find zu verwenden kombinieren (was den Vorteil hat, in Unterverzeichnisse zu rekursieren), zum Beispiel:

find ./ -type f -exec vim -c '%s/originalstring/replacementstring/gc' -c 'wq' {} \;
0
Anurag Bihani