Ich möchte Text in einer großen Anzahl von Dateien mit Ausnahme einiger Instanzen suchen und ersetzen. Ich möchte für jede Zeile eine Eingabeaufforderung, in der ich gefragt werde, ob ich diese Zeile ersetzen muss oder nicht. Ähnlich wie bei vim :%s/from/to/gc
(mit der c
Aufforderung zur Bestätigung), jedoch über eine Reihe von Ordnern hinweg. Gibt es ein gutes Befehlszeilentool oder Skript, das verwendet werden kann?
11
s/from/to/g
mit einem Formatierungsfehler danach gelesen , anstatt dens/from/to/gc
Schwerpunkt auf das zu legen,c
was Sie zu schreiben versucht hatten (das können Sie mit Markdown nicht tun, Sie könnten es tun<code>
und<strong>
HTML-Tags).Antworten:
Warum nicht vim verwenden?
Öffnen Sie alle Dateien in vim
Oder öffnen Sie nur relevante Dateien (wie von Caleb vorgeschlagen)
Führen Sie dann das Ersetzen in allen Puffern aus
Sie können es auch tun
sed
, aber mein Wissen ist begrenzt.quelle
grep
stattdessen verwenden,find
sodass Sie nur Dateien öffnen, deren Übereinstimmungen bekannt sind.vim $(grep 'from' . -Rl)
Mit einem kleinen Perl-Skript, das angewiesen wird, zeilenweise (
-l -pe
) Ersetzungen für die als Argumente übergebenen Dateien durchzuführen, können Sie etwas Grobes tun-i
:Mögliche Verbesserungen wären, Teile der Eingabeaufforderung einzufärben und Dinge wie "Alle Vorkommen in der aktuellen Datei ersetzen" zu unterstützen. Es wäre schwieriger, jedes Vorkommen in einer Zeile separat aufzufordern.
Zweiter Teil, passend zu den Dateien. Wenn nicht zu viele Dateien beteiligt sind und Sie zsh ausführen, können Sie alle Dateien im aktuellen Verzeichnis und seinen Unterverzeichnissen rekursiv abgleichen:
Wenn Ihre Shell bash ≥4 ist, können Sie ausführen
perl … **/*
, dies führt jedoch zu falschen Fehlermeldungen, da sed versucht (und fehlschlägt), in Verzeichnissen ausgeführt zu werden. Wenn Sie das Ersetzen nur in einer Reihe von Dateien wie C-Dateien durchführen möchten, können Sie die Übereinstimmungen einschränken (dies funktioniert entweder in Bash ≥4 oder zsh):Wenn Sie eine genauere Kontrolle darüber benötigen, welche Dateien Sie ersetzen, oder Ihre Shell nicht über das rekursive Verzeichnisvergleichskonstrukt
**
verfügt oder wenn Sie zu viele Dateien haben und den Fehler "Befehlszeile zu lang" erhalten, verwenden Siefind
. Um beispielsweise eine Ersetzung in allen Dateien mit dem Namen*.h
oder*.c
im aktuellen Verzeichnis und seinen Unterverzeichnissen durchzuführen (auf älteren Systemen müssen Sie diese möglicherweise\;
anstelle des+
Zeilenendes verwenden (das+
Formular ist schneller, aber nicht überall verfügbar).Davon abgesehen würde ich mich an einen interaktiven Editor halten, wenn Sie Interaktion benötigen. Gert hat in Vim einen Weg dazu aufgezeigt , erfordert jedoch das Öffnen aller Dateien, die Sie durchsuchen möchten. Dies kann ein Problem sein, wenn viele vorhanden sind.
In Emacs können Sie Folgendes tun:
M-x find-name-dired
(geben Sie ein Verzeichnis auf oberster Ebene an) oderM-x find-dired
(geben Sie eine beliebigefind
Befehlszeile an).t
um alle Dateien zu markieren, und dannQ
(dired-do-query-replace-regexp
) , um einen Ersatz mit Aufforderung für die markierten Dateien durchzuführen.quelle
sdiff
(siehe http://www.gnu.org/software/diffutils/manual/diffutils.html#Invoking-sdiff ) könnte hier nützlich sein. Damit können Sie interaktives Patchen durchführen. Daher kann essed
eine mögliche Lösung sein , dies mit einer temporären Datei zu tun, die Sie durch Ersetzen von Ersetzungsvorgängen mit erstellt haben :(Dateischleife mit Nicht-POSIX-Prozessersetzung und
read -d
wie zbash
. B. unterstützt .)quelle