ls mit glob funktioniert nicht in einem Bash-Skript

10

Ich muss alle Unterverzeichnisse eines Verzeichnisses auflisten, mit Ausnahme derjenigen, die mit einer Liste übereinstimmen, die als Argument angegeben wurde: "SUBDIR1, SUBDIR2, ..., SUBDIRN".

Ich kam mit der Lösung (aus vielen Quellen), ls mit einem Glob-Muster zu verwenden. Um das Konzept zu testen, habe ich in der Befehlszeile die folgende Sequenz ausprobiert, die zu funktionieren scheint:

DIR="/path/to/dirs"
EXCLUDELIST="subdir1,subdir2"
#transform in a glob pattern for excluding given subdirectories
EXCLUDE="!(${EXCLUDELIST//,/|})"
LIST=$(cd $DIR && ls -l -d $EXCLUDE | grep -E "(^d)" | awk '{print $9}')

Wenn ich es jedoch unverändert in ein Bash-Skript einfüge , wird dieser Fehler angezeigt

ls: cannot access !(subdir1|subdir2): No such file or directory

Was mache ich falsch, wenn ich diesen Code in das Skript einfüge?

Pablochacin
quelle

Antworten:

3

Dennis hat Ihnen erklärt, warum Ihr Skript fehlschlägt, aber ich möchte einen einfacheren (und sichereren) Weg vorschlagen, dies zu tun. Das Parsen lsist fast immer eine schlechte Idee , es kann leicht zu Dateinamen mit Leerzeichen oder neuen Zeilen oder anderen seltsamen Zeichen führen und ist in den LOCALE-Einstellungen nicht portierbar. Außerdem ist Ihr Befehl sehr komplex und umfasst mehrere Schritte. Warum nicht alles in find?

DIR="/path/to/dirs"
EXCLUDELIST="subdir1,subdir2"
## Build the regular expression
EXCLUDE="${EXCLUDELIST//,/|.*}"
LIST=$(find "$DIR" -type d -regextype posix-awk -not -regex ".*$EXCLUDE.*")

By the way, wird das Skript nicht , wie Sie es geschrieben haben , weil Sie die glob bauen vor cd -ing in $DIRso wird es in Bezug auf den Inhalt des aktuellen Verzeichnisses gebaut werden.

Terdon
quelle
Danke, es funktioniert, muss nur -printf "% f \ n" hinzufügen, um nur den Unterverzeichnisnamen (nicht den gesamten Pfad) zu erhalten. Übrigens ist das CD-Erstellen vor dem Glob beabsichtigt und funktioniert im interaktiven Modus.
Pablochacin
10

Interaktive und nicht interaktive Bash-Shells verhalten sich nicht gleich. Einer der vielen Unterschiede besteht darin, dass die Shell-Option extglob standardmäßig für interaktive Shells aktiviert ist (zumindest in meiner Version von bash), jedoch nicht für nicht interaktive.

Aktivieren Sie extglob mit dem folgenden Befehl , um Ihr Skript zu reparieren :

shopt -s extglob
Dennis
quelle
Durch Aktivieren dieser Option hat die Shell den Glob vor dem Ausführen des Befehls ls erweitert: ls -1 -d subdir3 subdir4 subdir5 ..... subdirn wobei die Liste der Unterverzeichnisse die tatsächliche Erweiterung des Glob ist.
Pablochacin
Ja, so funktionieren Globs. Ich glaube nicht, dass ich verstehe, was Sie damit meinen.
Dennis
Der Befehl shopt funktioniert in #!/bin/bashSkripten, jedoch nicht in #!/bin/sh(was auf meinem RHEL6-System tatsächlich Bash ist, aber die Verwendung dieses Namens weist es an, ein anderes Verhalten zu verwenden). Mein Google-Fu versagt mir, ich kann den entsprechenden Bourne-Shell-Befehl nicht finden.
Dan Pritts