it-swarm.com.de

Ersetzungsstring in xargs ändern

Wenn ich xargs verwende, muss ich die ersetzende Zeichenfolge manchmal nicht explizit verwenden:

find . -name "*.txt" | xargs rm -rf

In anderen Fällen möchte ich die ersetzende Zeichenfolge angeben, um folgende Aufgaben auszuführen:

find . -name "*.txt" | xargs -I '{}' mv '{}' /foo/'{}'.bar

Der vorherige Befehl würde alle Textdateien unter dem aktuellen Verzeichnis in /foo verschieben und die Erweiterung bar an alle Dateien anhängen.

Wenn ich den Text nicht an den Ersetzungsstring anfügen wollte, sondern ihn so ändern, dass er zwischen dem Namen und der Erweiterung der Dateien Text einfügen kann, wie kann ich das tun? Angenommen, ich möchte das gleiche wie im vorherigen Beispiel tun, aber die Dateien sollten umbenannt/verschoben werden von <name>.txt in /foo/<name>.bar.txt (anstelle von /foo/<name>.txt.bar).

UPDATE: Ich finde eine Lösung:

find . -name "*.txt" | xargs -I{} \
    sh -c 'base=$(basename $1) ; name=${base%.*} ; ext=${base##*.} ; \
           mv "$1" "foo/${name}.bar.${ext}"' -- {}

Aber ich frage mich, ob es eine kürzere/bessere Lösung gibt.

40
betabandido

In solchen Fällen wäre eine while-Schleife besser lesbar:

find . -name "*.txt" | while IFS= read -r pathname; do
    base=$(basename "$pathname"); name=${base%.*}; ext=${base##*.}
    mv "$pathname" "foo/${name}.bar.${ext}"
done

Beachten Sie, dass Sie möglicherweise Dateien mit demselben Namen in verschiedenen Unterverzeichnissen finden. Sind Sie in Ordnung, wenn Duplikate von mv überschrieben werden?

15
glenn jackman

Der folgende Befehl erstellt den Verschiebungsbefehl mit xargs und ersetzt das zweite Vorkommen von '.' mit '.bar.' führt dann die Befehle mit bash aus und arbeitet mit Mac OSX. 

ls *.txt | xargs -I {} echo mv {} foo/{} | sed 's/\./.bar./2' | bash
31
fairidox

Dies ist in einem Durchgang (getestet in GNU) möglich, sodass die temporären Variablenzuweisungen nicht verwendet werden

find . -name "*.txt" | xargs -I{} sh -c 'mv "$1" "foo/$(basename ${1%.*}).new.${1##*.}"' -- {}
16
Santrix

Wenn Sie GNU Parallel http://www.gnu.org/software/parallel/ installiert haben, können Sie Folgendes tun:

find . -name "*.txt" | parallel 'ext="{/}" ; mv -- {} foo/{/.}.bar.${ext##*.}'

In den Introvideos zu GNU Parallel erfahren Sie mehr: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

11
Ole Tange

Wenn Sie etwas anderes als bash/sh verwenden dürfen UND dies ist nur für ein schickes "mv" ... können Sie das ehrwürdige Skript "rename.pl" ausprobieren. Ich verwende es ständig unter Linux und cygwin unter Windows.

http://people.sc.fsu.edu/~jburkardt/pl_src/rename/rename.html

rename.pl 's/^(.*?)\.(.*)$/\1-new_stuff_here.\2/' list_of_files_or_glob

Sie können auch einen "-p" -Parameter zum Umbenennen von ".pl" verwenden, damit Sie wissen lassen, was es hätte tun sollen, ohne es tatsächlich zu tun.

Ich habe gerade folgendes in meiner c:/bin (cygwin/Windows-Umgebung) ausprobiert. Ich habe das "-p" verwendet, damit es ausspuckte, was es getan hätte. In diesem Beispiel werden Basis und Erweiterung nur geteilt und dazwischen eine Zeichenfolge eingefügt.

Perl c:/bin/rename.pl -p 's/^(.*?)\.(.*)$/\1-new_stuff_here.\2/' *.bat

rename "here.bat" => "here-new_stuff_here.bat"
rename "htmldecode.bat" => "htmldecode-new_stuff_here.bat"
rename "htmlencode.bat" => "htmlencode-new_stuff_here.bat"
rename "sdiff.bat" => "sdiff-new_stuff_here.bat"
rename "widvars.bat" => "widvars-new_stuff_here.bat"
2

die Dateien sollten umbenannt/verschoben werden von <name>.txt in /foo/<name>.bar.txt

Sie können das Dienstprogramm rename verwenden, z.

rename s/\.txt$/\.txt\.bar/g *.txt

Hinweis: Die Subsitutionssyntax ist sed oder vim ähnlich.

Verschieben Sie dann die Dateien mit mv in ein Zielverzeichnis:

mkdir /some/path
mv *.bar /some/path

Um Dateien in Unterverzeichnisse basierend auf einem Teil ihres Namens umzubenennen, prüfen Sie Folgendes:

-p/--mkpath/--make-dirs Erstellen Sie nicht vorhandene Verzeichnisse im Zielpfad.


Testen:

$ touch {1..5}.txt
$ rename --dry-run "s/.txt$/.txt.bar/g" *.txt
'1.txt' would be renamed to '1.txt.bar'
'2.txt' would be renamed to '2.txt.bar'
'3.txt' would be renamed to '3.txt.bar'
'4.txt' would be renamed to '4.txt.bar'
'5.txt' would be renamed to '5.txt.bar'
1
kenorb

Hinzu kommt, dass der Wikipedia-Artikel überraschend informativ ist

zum Beispiel:

Shell-Trick

Eine andere Möglichkeit, einen ähnlichen Effekt zu erzielen, besteht darin, eine Shell als gestarteten Befehl zu verwenden und sich beispielsweise mit der Komplexität dieser Shell auseinanderzusetzen:

$ mkdir ~/backups
$ find /path -type f -name '*~' -print0 | xargs -0 bash -c 'for filename; do cp -a "$filename" ~/backups; done' bash
0
Mike Graf

Inspiriert von einer Antwort von @justaname oben, wird dieser Befehl, der Perl-Einzeiler enthält, dies tun:

find ./ -name \*.txt | Perl -p -e 's/^(.*\/(.*)\.txt)$/mv $1 .\/foo\/$2.bar.txt/' | bash

0
Vasiliy