GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Manipulieren Sie {} Rückgabezeichenfolge von Find -exec?

Ich möchte es so effizient wie möglich machen, falls es viele Dateien geben wird.
Ich möchte alle Dateien, die ich gefunden habe, umbenennen und ihr Suffix entfernen.

Zum Beispiel:

[/tmp] $ ls -l
a.log
b.log
c.tmp
[/tmp] $ find /tmp -name "*.log" -type f -exec mv {} {%.*} \;
[/tmp] $ ls -l
a
b
c.tmp

Das funktioniert nicht. Wenn es eine normale Bash-Variable war ${var%.*} hätte var zurückgegeben bis zum letzten . .

Akzeptierte Antwort:

Starten Sie eine Shell, um Shell-Parametererweiterungsoperatoren zu verwenden:

find ~/tmp -name '*.log' -type f -exec sh -c '
  for file do
    mv -i -- "$file" "${file%.*}"
  done' sh {} +

Beachten Sie, dass Sie dies nicht auf /tmp tun möchten oder jedes Verzeichnis, das von anderen beschreibbar ist, da dies böswilligen Benutzern ermöglichen würde, Sie dazu zu bringen, beliebige .log umzubenennen Dateien im Dateisystem¹ (oder verschieben Sie Dateien in ein beliebiges Verzeichnis²).

Mit etwas find und mv Implementierungen können Sie find -execdir verwenden und mv -T um es sicherer zu machen:

find /tmp -name '*.log' -type f -execdir sh -c '
  for file do
    mv -Ti -- "$file" "${file%.*}"
  done' sh {} +

Oder verwenden Sie rename (die Perl-Variante), die nur ein rename() ausführen würde Systemaufruf, also versuchen Sie nicht, Dateien in andere Dateisysteme oder in Verzeichnisse zu verschieben...

find /tmp -name '*.log' -type f -execdir rename 's/\.log$//' {} +

Oder machen Sie das Ganze in perl :

perl -MFile::Find -le '
  find(
    sub {
      if (/\.log\z/) {
        $old = $_;
        s/\.log\z//;
        rename($old, $_) or warn "rename $old->$_: $!\n"
      }
    }, @ARGV)' ~/tmp

Beachten Sie jedoch, dass perl ’s Find::File (im Gegensatz zu GNU find ) führt kein sicheres Verzeichnis-Traversal³ durch, also möchten Sie das auf /tmp nicht tun entweder.

Notizen.

¹ Ein Angreifer kann einen /tmp/. /auth.log file, und dazwischen find finden und mv Wenn Sie es verschieben (und dieses Fenster kann leicht beliebig groß gemacht werden), ersetzen Sie den "/tmp/. " Verzeichnis mit einem symbolischen Link zu /var/log was zu /var/log/auth.log führt umbenannt in /var/log/auth

² Schlimmer noch, ein Angreifer kann eine /tmp/foo.log erstellen bösartiges crontab zum Beispiel und /tmp/foo ein symbolischer Link zu /etc/cron.d und lassen Sie diese Crontab in verschieben /etc/cron.d . Das ist die Mehrdeutigkeit bei mv (gilt auch für cp und ln zumindest), das kann beides sein move to und einziehen . GNU mv behebt es mit seinem -t (in ) und -T (nach ) Optionen.

Verwandt:Variables Datum im Sed-Befehl verwenden?

³ File::Find durchläuft das Verzeichnis mit chdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..")... . Also kann jemand einen /tmp/foo/bar erstellen Verzeichnis und benennen Sie es im richtigen Moment in /tmp/bar um also der chdir("../..") würde Sie in / landen .


Linux
  1. Wie finde ich eine Datei, deren Name eine bestimmte Zeichenfolge wie „abcde“ enthält?

  2. Brechen Sie von Find ab, wenn ein -exec fehlschlägt?

  3. Wie benenne ich mehrere Dateien mit Find um?

  4. find -exec cmd {} + vs | xargs

  5. finde -exec eine Shell-Funktion in Linux?

So finden Sie eine Zeichenfolge in einer Datei unter Linux

So finden Sie die Virtualbox-Version über die Befehlszeile in Linux

Entferne unbekannte Zeichen aus Zeichenfolge für -exec?

adb:Finden Sie PID aus der Adb-Shell

Dateiliste von der Suche ausschließen

Suchbefehl von PID