Klammern funktionieren in der Bash-Shell selbst, jedoch nicht im Bash-Skript

11

Ich kann diesen Befehl über meine Eingabeaufforderung ausführen:

cp -r folder/!(exclude-me) ./

Um alle Inhalte mit folder Ausnahme des genannten Unterverzeichnisses rekursiv exclude-mein das aktuelle Verzeichnis zu kopieren . Dies funktioniert genau wie vorgesehen. Ich brauche dies jedoch, um in einem von mir geschriebenen Bash-Skript zu arbeiten, in dem ich Folgendes habe:

if [ -d "folder" ]; then
  cp -r folder/!(exclude-me) ./
  rm -rf folder
fi

Aber wenn ich das Skript starte:

bash my-script.sh

Ich verstehe das:

my-script.sh: line 30: syntax error near unexpected token `('
my-script.sh: line 30: `  cp -r folder/!(exclude-me) ./'

Und ich weiß nicht, warum es an der Eingabeaufforderung funktioniert, aber genau dieselbe Zeile funktioniert in einem Bash-Skript nicht.

nzifnab
quelle

Antworten:

11

Dies liegt daran, dass die von Ihnen verwendete Syntax von einer bestimmten Bash-Funktion abhängt, die für nicht interaktive Shells (Skripte) nicht standardmäßig aktiviert ist. Sie können es aktivieren, indem Sie den entsprechenden Befehl zu Ihrem Skript hinzufügen:

## Enable extended globbing features
shopt -s extglob

if [ -d "folder" ]; then
  cp -r folder/!(exclude-me) ./
  rm -rf folder
fi

Dies ist der relevante Abschnitt von man bash:

   If the extglob shell option is enabled using the shopt builtin, several
   extended  pattern  matching operators are recognized.  In the following
   description, a pattern-list is a list of one or more patterns separated
   by a |.  Composite patterns may be formed using one or more of the fol
   lowing sub-patterns:

          ?(pattern-list)
                 Matches zero or one occurrence of the given patterns
          *(pattern-list)
                 Matches zero or more occurrences of the given patterns
          +(pattern-list)
                 Matches one or more occurrences of the given patterns
          @(pattern-list)
                 Matches one of the given patterns
          !(pattern-list)
                 Matches anything except one of the given patterns
terdon
quelle
Dies ist das zweite Mal, dass ich diese Antwort finde (ja, schlechtes Gedächtnis). Dieses Mal wurde versucht, run env > file1in das Skript zu setzen und auszuführen ./it, und dann env > file2und source itin der Hoffnung, dass ich einen Unterschied im envs gefunden hätte, was nicht der Fall ist. Wie kann ich programmgesteuert den Unterschied zwischen zwei Shells auflisten (in diesem Fall interaktiv und nicht interaktiv)?
Enrico Maria De Angelis
2

Fügen Sie diese Zeile oben in Ihrem Skript hinzu:

shopt -s extglob

!(...)ist eine erweiterte Mustervergleichsfunktion, extglobfür deren Verwendung Sie die Option aktivieren müssen. Weitere Informationen finden Sie unter Shopt Builtin .

cuonglm
quelle