Wie kopiere und füge ich Dateinamen in einem Schritt ein Präfix hinzu?

7

Ich möchte mehrere c-Quelldateien in einem Verzeichnis kopieren und umbenennen.

Ich kann so kopieren:

$ cp *.c $OTHERDIR

Aber ich möchte allen Dateinamen ein Präfix geben:

file.c --> old#file.c

Wie kann ich das in 1 Schritt machen?

Schwarze Katze
quelle

Antworten:

18

eine forSchleife:

for f in *.c; do cp -- "$f" "$OTHERDIR/old#$f"; done

Ich füge oft die -vOption hinzu, cpdamit ich den Fortschritt verfolgen kann.

Glenn Jackman
quelle
7

Sie können Shell Globbing verwenden:

for f in *.c; do cp -- "$f" "$OTHERDIR/old#$f"; done

Das for variable in GLOBFormat erweitert den Glob auf alle übereinstimmenden Dateien / Verzeichnisse (mit Ausnahme der versteckten) und iteriert über diese, wobei jede nacheinander als $variable(im obigen Beispiel $f) gespeichert wird . Der Befehl, den ich zeige, durchläuft also alle nicht versteckten Dateien, kopiert sie und fügt das Präfix hinzu.

terdon
quelle
Wenn ich das tue for f in /foo/bar/*.c, $fwird der gesamte Pfad enthalten, stattdessen nur der Name der Datei. Wie kann ich nur den Namen der Datei erhalten?
alexandernst
1
@alexandernst entweder cd /foo/bar/; for f in *coder verwenden for f in /foo/bar/*.c; do name=${f##*/} ...oder name=$(basename "$f").
Terdon
1

Noch ein anderer Weg:

for f in $(find dir/ -type f | grep -v 'bk_'); do cp -- "$f" "$(dirname $f)/bk_$(pwgen -s 4 1)_$(basename $f)"; done

Jedes Mal, wenn Sie auf diese Weise laufen, wird dir / from geändert:

dir/foo/foo.c
dir/bar/bar.c
dir/baz/baz.c

In:

dir/foo/foo.c
dir/foo/bk_R3pP_foo.c
dir/bar/bar.c
dir/bar/bk_o1JD_bar.c
dir/baz/baz.c
dir/baz/bk_0QqF_baz.c

Und dann:

dir/foo/foo.c
dir/foo/bk_R3pP_foo.c
dir/foo/bk_dV06_foo.c
dir/bar/bar.c
dir/bar/bk_o1JD_bar.c
dir/bar/bk_B68i_bar.c
dir/baz/baz.c
dir/baz/bk_0QqF_baz.c
dir/baz/bk_p6P3_baz.c

Und dann...:

dir/foo/foo.c
dir/foo/bk_R3pP_foo.c
dir/foo/bk_dV06_foo.c
dir/foo/bk_2Ar8_foo.c
dir/bar/bar.c
dir/bar/bk_o1JD_bar.c
dir/bar/bk_B68i_bar.c
dir/bar/bk_wX7Z_bar.c
dir/baz/baz.c
dir/baz/bk_0QqF_baz.c
dir/baz/bk_p6P3_baz.c
dir/baz/bk_fPd3_baz.c

.. und so weiter.

Hudson Santos
quelle
Schleifen Sie nicht über finddie Ausgabe . Verwenden Sie grepdiese Option nicht , um Dateinamen auszuschließen, wenn dies findalleine möglich ist.
don_crissti
0

Hier ist, wie man es bei Bedarf rekursiv machen würde:

for f in `find . -name \*.c`; do name="${f//\.\//__}"; fileName="${name//\//_}" ; echo "Copying $f as $OTHERDIR/old#$fileName"; cp -- "$f" "$OTHERDIR/$fileName"; done
Blueskin
quelle
Gleiches gilt hier nicht für finddie Ausgabe
don_crissti
0

Hier ist ein Einzeiler mit xargs, trund Globbing. Könnte einen Wert haben.

echo *.c | tr ' ' '\n' | xargs -n1 -I{} cp "{}" "PREFIX{}"

Dies gibt alle übereinstimmenden Dateien *.cals durch Leerzeichen getrennte Zeichenfolge zurück. Als nächstes werden trdie zusätzlichen Leerzeichen in Zeilenumbrüche umgewandelt ( NB hat Dateinamen nicht mit Leerzeichen ** getestet). Wird xargsdann mit jedem Dateinamen gefüllt und cpmit dem entsprechenden Namen und Präfix ausgeführt.

*.ckann für andere nützliche Globs geändert werden. Andere Präfixe im Teil xargsund cpkönnen ebenfalls verwendet werden.

** für diejenigen mit Leerzeichen in ihren Dateinamen:

(erfordert findUnterstützung -print0) Ähnlich wie oben können wir findeine durch Null getrennte Liste von Dateien ausgeben und xargsmit einem Flag optimieren , um bei Null zu trennen

find . -name '*.c' -print0 | xargs -0 -n1 -I{} cp "{}" "PREFIX{}"
TonyH
quelle
1
Und wenn Sie hatte dies mit Dateinamen Leerzeichen enthalten , getestet, würden Sie sehen es nicht.
Scott
1
Danke für den Anruf. Ich wusste, dass es wahrscheinlich fehlgeschlagen war, dachte aber, ich hätte meinen ersten Arbeitstag bereits mit dem ersten Durchgang verschoben. 😀
TonyH