webentwicklung-frage-antwort-db.com.de

Benennen Sie mehrere Dateien in Unix um

Es gibt mehrere Dateien in einem Verzeichnis, die mit dem Präfix fgh beginnen, zum Beispiel:

fghfilea
fghfileb
fghfilec

Ich möchte alle umbenennen, um mit dem Präfix jkl zu beginnen. Gibt es einen einzelnen Befehl, um das zu tun, anstatt jede Datei einzeln umzubenennen?

202
john

Es gibt mehrere Möglichkeiten, aber die Verwendung von rename ist wahrscheinlich die einfachste.

Verwendung einer Version von rename :

rename 's/^fgh/jkl/' fgh*

Verwendung einer anderen Version von rename (identisch mit Judy2Ks Antwort ):

rename fgh jkl fgh*

Sie sollten in der Manpage Ihrer Plattform nachsehen, welche der oben genannten Bedingungen zutreffend ist.

248
Stephan202

So können sed und mv zusammen zum Umbenennen verwendet werden:

for f in fgh*; do mv "$f" $(echo "$f" | sed 's/^fgh/jkl/g'); done

Laut Kommentar unten, wenn die Dateinamen Leerzeichen enthalten, müssen möglicherweise Anführungszeichen Surround die Unterfunktion sein, die den Namen zurückgibt, in den die Dateien verschoben werden sollen:

for f in fgh*; do mv "$f" "$(echo $f | sed 's/^fgh/jkl/g')"; done
102
nik

umbenennen möglicherweise nicht in jedem System. Wenn Sie es nicht haben, verwenden Sie die Shell dieses Beispiel in der Bash-Shell

for f in fgh*; do mv "$f" "${f/fgh/xxx}";done
68
ghostdog74

Verwendung von mmv :

mmv "fgh*" "jkl#1"
35
Lee Netherton

Es gibt viele Möglichkeiten, dies zu tun (nicht alle funktionieren auf allen Unixy-Systemen): 

  • ls | cut -c4- | xargs -I§ mv fgh§ jkl§

    Der § kann durch alles ersetzt werden, was Sie für bequem halten. Das könnte man auch mit find -exec machen, aber das verhält sich auf vielen Systemen subtil anders, daher vermeide ich das normalerweise

  • for f in fgh*; do mv "$f" "${f/fgh/jkl}";done 

    Roh, aber effektiv wie sie sagen 

  • rename 's/^fgh/jkl/' fgh*

    Wirklich hübsch, aber das Umbenennen ist auf BSD, dem am häufigsten verwendeten Unix-System von afaik, nicht vorhanden.

  • rename fgh jkl fgh*

  • ls | Perl -ne 'chomp; next unless -e; $o = $_; s/fgh/jkl/; next if -e; rename $o, $_';

    Wenn Sie darauf bestehen, Perl zu verwenden, es aber auf Ihrem System keine Umbenennung gibt, können Sie dieses Monster verwenden.

Einige davon sind etwas kompliziert und die Liste ist bei weitem nicht vollständig, aber Sie werden hier für fast alle Unix-Systeme finden, was Sie wollen.

18
iwein
rename fgh jkl fgh*
12
Judy2K

Verwendung von find, xargs und sed:

find . -name "fgh*" -type f -print0 | xargs -0 -I {} sh -c 'mv "{}" "$(dirname "{}")/`echo $(basename "{}") | sed 's/^fgh/jkl/g'`"'

Es ist komplexer als die Lösung von @ nik , aber es erlaubt das rekursive Umbenennen von Dateien. Zum Beispiel die Struktur,

.
├── fghdir
│   ├── fdhfilea
│   └── fghfilea
├── fghfile\ e
├── fghfilea
├── fghfileb
├── fghfilec
└── other
    ├── fghfile\ e
    ├── fghfilea
    ├── fghfileb
    └── fghfilec

würde in dieses umgewandelt werden,

.
├── fghdir
│   ├── fdhfilea
│   └── jklfilea
├── jklfile\ e
├── jklfilea
├── jklfileb
├── jklfilec
└── other
    ├── jklfile\ e
    ├── jklfilea
    ├── jklfileb
    └── jklfilec

Der Schlüssel, mit dem es mit xargs funktioniert, ist die Shell von xargs aufzurufen.

8
luissquall

So installieren Sie das Perl umbenennen -Skript: 

Sudo cpan install File::Rename

Es gibt zwei Umbenennungen wie in den Kommentaren in der Antwort von Stephan202 erwähnt . Debian-basierte Distributionen haben die Perl-Umbenennung . Redhat/rpm Distros haben die C umbenennen .
Auf OS X ist standardmäßig kein Betriebssystem installiert (zumindest in 10.8). Windows/Cygwin ist ebenfalls nicht installiert. 

3
Sam Inverso

Hier ist eine Möglichkeit, dies mit der Befehlszeile Groovy zu tun:

groovy -e 'new File(".").eachFileMatch(~/fgh.*/) {it.renameTo(it.name.replaceFirst("fgh", "jkl"))}'
2
jesseplymale

Unter Solaris können Sie Folgendes versuchen:

for file in `find ./ -name "*TextForRename*"`; do 
    mv -f "$file" "${file/TextForRename/NewText}"
done
2
#!/bin/sh

#replace all files ended witn .f77 to .f90 in a directory

for filename in *.f77
do 
    #echo $filename
    #b= echo $filename | cut -d. -f1
    #echo $b    
    mv "${filename}" "${filename%.f77}.f90"    
done
2
Suragini

Ich würde empfehlen, mein eigenes Skript zu verwenden, um dieses Problem zu lösen. Es gibt auch Optionen, um die Kodierung der Dateinamen zu ändern und das Kombinieren von Diakritischen Zeichen in vorkomponierte Zeichen umzuwandeln. Dieses Problem habe ich immer, wenn ich Dateien von meinem Mac kopiere.

#!/usr/bin/Perl

# Copyright (c) 2014 André von Kugland

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

$help_msg =
"rename.pl, a script to rename files in batches, using Perl
           expressions to transform their names.
Usage:
    rename.pl [options] FILE1 [FILE2 ...]
Where options can be:
    -v                      Verbose.
    -vv                     Very verbose.
    --apply                 Really apply modifications.
    -e PERLCODE             Execute PERLCODE. (e.g. 's/a/b/g')
    --from-charset=CS       Source charset. (e.g. \"iso-8859-1\")
    --to-charset=CS         Destination charset. (e.g. \"utf-8\")
    --unicode-normalize=NF  Unicode normalization form. (e.g. \"KD\")
    --basename              Modifies only the last element of the path.
";

use Encode;
use Getopt::Long;
use Unicode::Normalize 'normalize';
use File::Basename;
use I18N::Langinfo qw(langinfo CODESET);

Getopt::Long::Configure ("bundling");

# ----------------------------------------------------------------------------------------------- #
#                                           Our variables.                                        #
# ----------------------------------------------------------------------------------------------- #

my $apply = 0;
my $verbose = 0;
my $help = 0;
my $debug = 0;
my $basename = 0;
my $unicode_normalize = "";
my @scripts;
my $from_charset = "";
my $to_charset = "";
my $codeset = "";

# ----------------------------------------------------------------------------------------------- #
#                                        Get cmdline options.                                     #
# ----------------------------------------------------------------------------------------------- #

$result = GetOptions ("apply" => \$apply,
                      "verbose|v+" => \$verbose,
                      "execute|e=s" => \@scripts,
                      "from-charset=s" => \$from_charset,
                      "to-charset=s" => \$to_charset,
                      "unicode-normalize=s" => \$unicode_normalize,
                      "basename" => \$basename,
                      "help|h|?" => \$help,
                      "debug" => \$debug);

# If not going to apply, then be verbose.
if (!$apply && $verbose == 0) {
  $verbose = 1;
}

if ((($#scripts == -1)
  && (($from_charset eq "") || ($to_charset eq ""))
  && $unicode_normalize eq "")
  || ($#ARGV == -1) || ($help)) {
  print $help_msg;
  exit(0);
}

if (($to_charset ne "" && $from_charset eq "")
  ||($from_charset eq "" && $to_charset ne "")
  ||($to_charset eq "" && $from_charset eq "" && $unicode_normalize ne "")) {
  $codeset = langinfo(CODESET);
  $to_charset = $codeset if $from_charset ne "" && $to_charset eq "";
  $from_charset = $codeset if $from_charset eq "" && $to_charset ne "";
}

# ----------------------------------------------------------------------------------------------- #
#         Composes the filter function using the @scripts array and possibly other options.       #
# ----------------------------------------------------------------------------------------------- #

$f = "sub filterfunc() {\n    my \$s = shift;\n";
$f .= "    my \$d = dirname(\$s);\n    my \$s = basename(\$s);\n" if ($basename != 0);
$f .= "    for (\$s) {\n";
$f .= "        $_;\n" foreach (@scripts);   # Get scripts from '-e' opt. #
# Handle charset translation and normalization.
if (($from_charset ne "") && ($to_charset ne "")) {
  if ($unicode_normalize eq "") {
    $f .= "        \$_ = encode(\"$to_charset\", decode(\"$from_charset\", \$_));\n";
  } else {
    $f .= "        \$_ = encode(\"$to_charset\", normalize(\"$unicode_normalize\", decode(\"$from_charset\", \$_)));\n"
  }
} elsif (($from_charset ne "") || ($to_charset ne "")) {
    die "You can't use `from-charset' nor `to-charset' alone";
} elsif ($unicode_normalize ne "") {
  $f .= "        \$_ = encode(\"$codeset\", normalize(\"$unicode_normalize\", decode(\"$codeset\", \$_)));\n"
}
$f .= "    }\n";
$f .= "    \$s = \$d . '/' . \$s;\n" if ($basename != 0);
$f .= "    return \$s;\n}\n";
print "Generated function:\n\n$f" if ($debug);

# ----------------------------------------------------------------------------------------------- #
#                 Evaluates the filter function body, so to define it in our scope.               #
# ----------------------------------------------------------------------------------------------- #

eval $f;

# ----------------------------------------------------------------------------------------------- #
#                  Main loop, which passes names through filters and renames files.               #
# ----------------------------------------------------------------------------------------------- #

foreach (@ARGV) {
  $old_name = $_;
  $new_name = filterfunc($_);

  if ($old_name ne $new_name) {
    if (!$apply or (rename $old_name, $new_name)) {
      print "`$old_name' => `$new_name'\n" if ($verbose);
    } else {
      print "Cannot rename `$old_name' to `$new_name'.\n";
    }
  } else {
    print "`$old_name' unchanged.\n" if ($verbose > 1);
  }
}
1

In Ruby war das viel einfacher (auf meinem Mac). Hier sind 2 Beispiele:

# for your fgh example. renames all files from "fgh..." to "jkl..."
files = Dir['fgh*']

files.each do |f|
  f2 = f.gsub('fgh', 'jkl')
  system("mv #{f} #{f2}")
end

# renames all files in directory from "021roman.rb" to "021_roman.rb"
files = Dir['*rb'].select {|f| f =~ /^[0-9]{3}[a-zA-Z]+/}

files.each do |f|
  f1 = f.clone
  f2 = f.insert(3, '_')
  system("mv #{f1} #{f2}")
end
1
Raymond Gan

Meine Version zum Umbenennen von Massendateien:

for i in *; do
    echo "mv $i $i"
done |
sed -e "s#from_pattern#to_pattern#g” > result1.sh
sh result1.sh
1
mdev

Renamer :

$ renamer --find /^fgh/ --replace jkl * --dry-run

Entfernen Sie das Flag --dry-run, sobald Sie zufrieden sind, dass die Ausgabe richtig aussieht.

1
Lloyd

Verwenden Sie StringSolver tools (Windows & Linux-Bash), die anhand von Beispielen vorgehen:

filter fghfilea ok fghreport ok notfghfile notok; mv --all --filter fghfilea jklfilea

Zuerst berechnet einen Filter anhand von Beispielen, wobei die Eingabe die Dateinamen und die Ausgabe sind (ok und notok, beliebige Zeichenfolgen). Wenn der Filter die Option --auto hatte oder nach diesem Befehl alleine aufgerufen wurde, würde er einen Ordner ok und einen Ordner notok und Push-Dateien erstellen.

Der Befehl mv verwendet dann den Filter und ist eine halbautomatische Bewegung, die mit dem Modifikator --auto automatisch wird. Mit dem vorherigen Filter dank --filter findet er eine Zuordnung von fghfilea zu jklfilea und wendet sie dann auf alle gefilterten Dateien an.


Andere einzeilige Lösungen

Andere gleichwertige Methoden, um dasselbe zu tun (jede Zeile ist gleichwertig), sodass Sie Ihre bevorzugte Methode wählen können.

filter fghfilea ok fghreport ok notfghfile notok; mv --filter fghfilea jklfilea; mv
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter fghfilea "mv fghfilea jklfilea"
# Even better, automatically infers the file name
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter "mv fghfilea jklfilea"

Mehrschrittlösung

Um genau zu ermitteln, ob die Befehle ordnungsgemäß ausgeführt werden, können Sie Folgendes eingeben:

filter fghfilea ok
filter fghfileb ok
filter fghfileb notok

und wenn Sie sicher sind, dass der Filter gut ist, führen Sie den ersten Schritt aus:

mv fghfilea jklfilea

Wenn Sie den vorherigen Filter testen und verwenden möchten, geben Sie Folgendes ein:

mv --test --filter

Wenn die Umwandlung nicht Ihren Wünschen entspricht (z. B. mit mv --explain Sie sehen, dass etwas nicht stimmt), können Sie mv --clear eingeben, um das Verschieben von Dateien erneut zu starten, oder weitere Beispiele hinzufügen mv input1 input2, wobei input1 und input2 weitere Beispiele sind

Wenn Sie zuversichtlich sind, tippen Sie einfach

mv --filter

und voilà! Alle Umbenennungen erfolgen mithilfe des Filters.

HAFTUNGSAUSSCHLUSS: Ich bin ein Co-Autor dieser Arbeit für akademische Zwecke. Es könnte auch bald eine Bash-Funktion geben.

1
Mikaël Mayer

Ich habe dieses Skript geschrieben, um nach allen .mkv-Dateien zu suchen, die gefundene Dateien rekursiv in .avi umbenennen. Sie können es an Ihre Bedürfnisse anpassen. Ich habe einige andere Dinge hinzugefügt, wie das Abrufen des Dateiverzeichnisses, der Erweiterung und des Dateinamens aus einem Dateipfad, nur wenn Sie in der Zukunft auf etwas Bezug nehmen müssen. 

find . -type f -name "*.mkv" | while read fp; do 
fd=$(dirname "${fp}");
fn=$(basename "${fp}");
ext="${fn##*.}";
f="${fn%.*}";
new_fp="${fd}/${f}.avi"
mv -v "$fp" "$new_fp" 
done;
0
David Okwii

Das funktionierte für mich mit regexp:

Ich wollte, dass Dateien so umbenannt werden:

file0001.txt -> 1.txt
ofile0002.txt -> 2.txt 
f_i_l_e0003.txt -> 3.txt

verwenden Sie die [a-z | _] + 0 * ([0-9] +.) -Erweiterung, wobei ([0-9] +. ) ein Gruppensubstring ist, der für den Umbenennungsbefehl verwendet werden soll

ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)/, arr) { print   arr[0]  " "  arr[1] }'|xargs  -l mv

Produziert:

mv file0001.txt 1.txt
mv ofile0002.txt 2.txt
mv f_i_l_e0003.txt 3.txt

Ein anderes Beispiel:

file001abc.txt -> abc1.txt
ofile0002abcd.txt -> abcd2.txt 

ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)([a-z]+)/, arr) { print   arr[0]  " "  arr[2] arr[1] }'|xargs  -l mv

Produziert:

  mv file001abc.txt abc1.txt
  mv ofile0002abcd.txt abcd2.txt 

Achtung, sei vorsichtig.

0
Steven Lizarazo

Weitere mögliche Parametererweiterung :

for f in fgh*; do mv -- "$f" "jkl${f:3}"; done
0
PesaThe

Ein generisches Skript zum Ausführen eines sed-Ausdrucks in einer Liste von Dateien (kombiniert die sed-Lösung mit der rename-Lösung )

#!/bin/sh

e=$1
shift

for f in $*; do
    fNew=$(echo "$f" | sed "$e")
    mv "$f" "$fNew";
done

Rufen Sie durch Übergeben des Skripts einen sed-Ausdruck und anschließend eine Liste von Dateien auf, genau wie bei einer Version von rename :

script.sh 's/^fgh/jkl/' fgh*
0
palswim

Sie können auch das folgende Skript verwenden. es ist sehr einfach am Terminal zu laufen ...

// Mehrere Dateien gleichzeitig umbenennen

for file in  FILE_NAME*
do
    mv -i "${file}" "${file/FILE_NAME/RENAMED_FILE_NAME}"
done

Beispiel: -

for file in  hello*
do
    mv -i "${file}" "${file/hello/JAISHREE}"
done
0
Sanjay Singh