it-swarm.com.de

rM löscht Dateien nicht als Platzhalter aus einem Skript, funktioniert jedoch über eine Shell-Eingabeaufforderung

Ich bin mit einem Linux-Shell-Skript in ein wirklich dummes Problem geraten. Ich möchte alle Dateien mit der Erweiterung ".bz2" in einem Verzeichnis löschen. Im Skript rufe ich an

rm "$archivedir/*.bz2"

dabei ist $ archivedir ein Verzeichnispfad. Sollte ziemlich einfach sein, oder? Irgendwie scheitert es an diesem Fehler:

rm: cannot remove `/var/archives/monthly/April/*.bz2': No such file or directory

Es gibt aber is eine Datei in diesem Verzeichnis namens test.bz2 und wenn ich mein Skript in ändere

echo rm "$archivedir/*.bz2"

kopieren Sie die Ausgabe dieser Zeile in ein Terminalfenster, und die Datei wird erfolgreich entfernt. Was mache ich falsch?

53
EMP

TL; DR

Zitieren Sie nur die Variable und nicht den gesamten erwarteten Pfad mit dem Platzhalterzeichen

rm "$archivedir"/*.bz2

Erklärung

  • In Unix interpretieren Programme im Allgemeinen keine Platzhalter selbst. Die Shell interpretiert nicht mit Anführungszeichen gesetzte Platzhalterzeichen und ersetzt jedes Platzhalterargument durch eine Liste übereinstimmender Dateinamen. Wenn $ archivedir Leerzeichen enthält, kann rm $archivedir/*.bz2 möglicherweise nicht das tun, was Sie tun 

  • Sie können diesen Vorgang deaktivieren, indem Sie das Platzhalterzeichen, doppelte oder einfache Anführungszeichen oder einen umgekehrten Schrägstrich voranstellen. Dies ist jedoch nicht das, was Sie hier wollen, sondern Sie möchten, dass der Platzhalter auf die Liste der Dateien erweitert wird, auf die er passt.

  • Seien Sie vorsichtig beim Schreiben von rm $archivedir/*.bz2 (ohne Anführungszeichen). Die Aufteilung des Wortes (d. H. Das Aufteilen der Befehlszeile in Argumente) geschieht , nachdem $ archivedir ersetzt wurde. Wenn $ archivedir Leerzeichen enthält, erhalten Sie zusätzliche Argumente, die Sie nicht beabsichtigen. Sagen wir, archivedir ist /var/archives/monthly/April to June. Dann erhalten Sie das Äquivalent des Schreibens von rm /var/archives/monthly/April to June/*.bz2, das versucht, die Dateien "/ var/archives/Monthly/April", "bis" und alle Dateien zu löschen, die mit "June/*. Bz2" übereinstimmen wollen.

Die richtige Lösung ist zu schreiben:

rm "$ archivedir"/*. bz2
99
Doug

Ihre ursprüngliche Zeile

rm "$archivedir/*.bz2"

Kann als neu geschrieben werden

rm "$archivedir"/*.bz2

den gleichen Effekt erzielen. Die Platzhaltererweiterung wird in Ihrem vorhandenen Setup nicht ordnungsgemäß ausgeführt. Indem Sie das Anführungszeichen (das ist legitim) in den "vorderen" Bereich des Dateipfads verschieben, vermeiden Sie dies.

10
Avery Payne

Um dies etwas zu erweitern, hat bash ziemlich komplizierte Regeln für den Umgang mit Metazeichen in Anführungszeichen. Im Algemeinen

  • in einfachen Anführungszeichen wird fast nichts interpretiert:

     echo '$foo/*.c'                  => $foo/*.c
     echo '\\*'                       => \\*
    
  • Die Shell-Ersetzung erfolgt in doppelten Anführungszeichen, aber die Datei-Metazeichen werden nicht erweitert:

     FOO=hello; echo "$foo/*.c"       => hello/*.c
    
  • alles in den Backquotes wird an die Subshell übergeben, die sie interpretiert. Eine Shell-Variable, die nicht exportiert wird, wird nicht in der Subshell definiert. Der erste Befehl ist also leer, aber das zweite und dritte Echo "tschüss":

    BAR=bye echo `echo $BAR`
    BAR=bye; echo `echo $BAR`
    export BAR=bye; echo `echo $BAR`
    

(Und das bekommen, um so zu drucken, wie Sie es wollen, in SO dauert mehrere Versuche ist scheinbar unmöglich ...)

9
Charlie Martin

Die Anführungszeichen bewirken, dass die Zeichenfolge als Zeichenfolgenliteral interpretiert wird. Versuchen Sie, sie zu entfernen. 

4

Warum nicht einfach rm -rf */*.bz2? Funktioniert für mich unter OSX.

0
holms

Ich habe ähnliche Fehler beim Aufruf eines Shell-Skripts wie ./Shell_script.sh .__ gesehen. von einem anderen Shell-Skript. Dies kann behoben werden, indem Sie es wie folgt aufrufen: __. sh Shell_script.sh

0
Christo