Wie kann ich Platzhalter im ms-dos-Stil mit ls und mv verwenden?

9

Ich habe das Unglück, aus einem MS-DOS-Hintergrund zu kommen - aber zumindest weiß ich zu schätzen, wie viel leistungsfähiger Linux ist. Ich habe daran gearbeitet, mein Linux-Fu auf den neuesten Stand zu bringen, aber es gibt einige Dinge, die mit DOS erledigt werden könnten, und ich bin mir nicht sicher, wie ich es mit Linux am einfachsten erreichen kann :

Umbenennen mehrerer Dateien - Verwenden von zwei Platzhaltern

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\>rename *.txt *.bak

c:\> dir

Directory of c:\
    file1.bak
    file2.bak
    file3.bak
    file4.bak

Ich weiß, dass ich hier verwenden könnte find -exec, aber ist es möglich, eine kürzere Syntax zu verwenden - vielleicht mvmit einigen speziellen Flags oder Syntax? Ich denke, der Schlüssel dazu ist der zweite * Platzhalter, da Linux kein Problem mit dem ersten haben sollte (dh ich weiß, wie man die Dateien auswählt, die ich mit Platzhaltern umbenennen möchte).

Umbenennen einer einzelnen Datei - Verwenden eines Platzhalters

c:\> dir

Directory of c:\
    file1.txt

c:\>rename file1.txt *.bak

c:\> dir

Directory of c:\
    file1.bak

Dies ist besonders hilfreich, wenn Sie lange und unhandliche Dateinamen umbenennen. Ich dachte, ich könnte vielleicht mv file1.txt $1.bakdamit enden, file1.txt.bakwas auch akzeptabel wäre, aber ich bin nicht sicher, ob Sie den $1Parameter inline mit einem Shell-Befehl referenzieren können . Auch in diesem speziellen Fall ist es nur praktisch, wie ms-dos den *Platzhalter bastardisiert , um ihn als eine Art Erfassungs- / Ersetzungsübereinstimmung für einen Teil des Dateinamens zu verwenden.

Filtern von Verzeichnislisten mit einem Platzhalter

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt
    text.txt
    \temp       (directory) 

c:\> dir file*

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\> t*

Directory of c:\
    text.txt
    \temp       (directory) 

Ich bin mir nicht sicher, mit welcher Syntax das richtig lsist oder ob es überhaupt möglich ist. Wenn ich so etwas getan habe ls t*, wird es von Anfang an in Verzeichnisse zurückgeführt t. Meine Problemumgehung wurde entweder verwendet find . --max-depth 1 -iname "t*"oder so ähnlich ls -al | grep t- keine davon ist so kurz und einfach wie sie dir t*ist.

Schließlich weiß ich, dass ich Aliase einrichten kann, um diese langen Befehle zu verkürzen, aber ich würde gerne ein sofort einsatzbereites Linux-Fu lernen, um diese Dinge zu tun, da Sie manchmal mit einem Remote-System verbunden sind oder arbeiten auf einer neuen Maschine.

Wie kann ich mvund lsDateien auf die gleiche Weise wie früher dirund renameDateien?

cwd
quelle

Antworten:

15

Einer der grundlegenden Unterschiede zwischen Windows- cmdund POSIX-Shells besteht darin, wer für Platzhaltererweiterungen verantwortlich ist. Shells führen alle erforderlichen Erweiterungen durch, bevor die von Ihnen angeforderten Befehle gestartet werden. Übergibt die Platzhaltermuster cmd meist unverändert an die Befehle. (Ich sage meistens, da ich denke, dass es Ausnahmen gibt und Umgebungsvariablen unter den meisten Umständen erweitert werden.) Dies macht das Schreiben eines rename, das mit der gleichen Syntax wie in cmdziemlich schwierig funktionieren würde .

Aber es gibt eine renamefür Linux - mit völlig anderen Argumenten lesen Sie die Manpage (die auf meinem System etwas knapp ist und renameaus dem util-linuxPaket auf meinem System stammt, das allgemein verfügbar sein sollte). Ihre erste Umbenennung würde folgendermaßen erfolgen:

rename .txt .bak *.txt

Beachten Sie, dass die Shell die *Erweiterung ausführt, sodass sie renameselbst denkt, dass sie wie folgt aufgerufen wurde:

rename .txt .bak file1.txt file2.txt file3.txt ...

Sie können also die Einzeldateiversion erraten:

rename .txt .bak file1.txt

Wenn Sie dies nicht verwenden, renamesondern selbst implementieren möchten , können Sie eine Funktion dafür erstellen. Angenommen, Sie möchten nur die Dateierweiterung ändern, und sehen Sie sich zum Umbenennen einzelner Dateien Folgendes an:

$ function chext() {
  newext="$1"
  file="$2"
  newfile="${file%.*}$newext"
  echo mv "$file" "$newfile"
}
$ chext .csv test.txt
mv text.txt text.csv

$newfilewird mithilfe einer Teilzeichenfolgenentfernung erstellt , um die ursprüngliche Erweiterung zu entfernen , und verkettet dann die neue Erweiterung. Sie können diese Funktion erweitern, um mehrere Dateien relativ einfach zu verarbeiten.


lsVerwenden Sie für Ihre Frage den -dSchalter. Dadurch wird verhindert, dass lsder Inhalt von Verzeichnissen aufgelistet wird.

Demo:

$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:29 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.csv
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

Platzhalter umbenennen

$ rename .csv .txt f*
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

Umbenennen einzelner Dateien

$ rename .txt .csv f1.txt 
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

Der Standard ls

$ ls -l t*
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv

test:
total 0
-rw-r--r-- 1 owner users 0 Jan  7 17:33 dont_show_me_please

ls das überprüft keine Verzeichnisse

$ ls -ld t*
drwxr-xr-x 2 owner users 4096 Jan  7 17:33 test
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv
Matte
quelle
Sehr schön! Ich glaube, ich habe gerade einen Gürtel mit meinem Linux-Fu hochgezogen! Vielen Dank!
CWD
Tipp, um ein wenig damit fortzufahren (und Fallstricke zu vermeiden): Verwenden Sie einfache Funktionen oder Skripte, um zu sehen, was passiert, somefunc *.Extwenn dieses Muster nicht mit einer Datei übereinstimmt, und spielen Sie mit Zitaten, um festzustellen, ob Sie es schaffen, ein Muster weiterzugeben ( ohne es erweitern zu lassen) zwischen Funktionen. Sicherheitstipp: Verwenden Sie nichts , rmwährend Sie mit Globbing / Shell-Expansion experimentieren :-)
Mat
4

Eine Sache, die Sie bei Platzhaltern beachten sollten, ist, dass sie durch die Shell erweitert werden. Die Anwendung weiß nicht, ob Sie Platzhalter verwendet oder die Namen eingegeben haben. Wenn Sie beispielsweise eingeben rename *.txt *.bak, renamesieht der Befehl so etwas wie rename file1.txt file2.txt existingfile.bak. Das sind nicht genug Informationen, um fortzufahren.

Ich werde mich zuerst mit der Frage befassen ls, weil es einfacher ist. Wenn Sie nur die passenden Namen möchten, brauchen Sie diese nicht ls, da die Shell bereits die Erweiterung durchführt.

echo t*

Wenn Sie weitere Informationen zu den Dateien wünschen, übergeben Sie die -dOption an ls, um anzugeben, dass der Inhalt von Verzeichnissen nicht aufgelistet werden soll.

ls -ld t*

Es gibt kein Standarddienstprogramm zum Umbenennen von Dateien, da die ersten Unix-Systeme keine hatten. Die portable Methode zum Umbenennen von Dateien verwendet eine Schleife und ist etwas ausführlich:

for x in *.txt; do mv -- "$x" "${x%.txt}.bak"; done

Es gibt mehrere gängige Dienstprogramme zum Umbenennen von Dateien, von denen keines garantiert auf einem bestimmten Unix-System installiert ist, die jedoch alle einfach zu installieren sind. Hier sind die wichtigsten:

  • renameaus der util-linuxSuite, verfügbar auf jedem nicht eingebetteten Linux-System (und nirgendwo anders). Unter Debian und Derivaten (einschließlich Ubuntu) wird dieser Befehl aufgerufen rename.ul. Sofern nur .txtdie endgültige Erweiterung auftritt, können Sie schreiben

    rename .txt .bak *.txt
    
  • renameist ein Perl-Skript, als das Debian und Derivate ausgeliefert werden /usr/bin/rename. Sie können Dateien nach beliebigen Perl-Befehlen umbenennen.

    rename 's/\.txt\z/\.bak/' *.txt
    
  • mmvDies kann Dateien nach verschiedenen namenbasierten Mustern umbenennen, kopieren und verknüpfen und bietet viele Optionen in Bezug darauf, was passiert, wenn bereits ein Zielname vorhanden ist. Beachten Sie, dass Sie Anführungszeichen verwenden müssen, um Platzhalter vor der Erweiterung durch die Shell zu schützen.

    mmv '*.txt' '#1.txt'
    
  • zmvist eine zsh- Funktion, die genau dann verfügbar ist, wenn Ihre Shell zsh ist. Es kann mit beliebigen zsh-Mustern übereinstimmen (Sie können also Dateinamen nach beliebigen regulären Ausdrücken und nicht nur nach Platzhaltern abgleichen und Dateien nach anderen Kriterien wie Datum und Größe abgleichen). zmvkann auch kopieren und verlinken.

    zmv '(*).txt' '$1.txt'
    

Wenn Sie die Kontrolle über die von Ihnen verwendeten Maschinen haben, empfehle ich, zsh als Shell zu verwenden (es hat andere Vorteile gegenüber bash) und diese Zeilen in Ihre ~/.zshrc:

autoload -U zmv
alias zmv='noglob zmv -w'
alias zcp='zmv -C'
alias zln='zmv -L'
alias zsy='zmv -Ls'

noglobist eine zsh-Funktion, die die Shell anweist, im Argument des Befehls keine Platzhalter zu erweitern. Auf diese Weise können Sie schreiben zmv *.txt \$1.txt(Sie müssen das immer $in einem Ersatztext schützen ).

Gilles 'SO - hör auf böse zu sein'
quelle