Ignorieren Sie „keine Übereinstimmungen“ von zsh, wenn Sie die Klammernerweiterung mit glob *.{a,b,}test verwenden

Ignorieren Sie „keine Übereinstimmungen“ von zsh, wenn Sie die Klammernerweiterung mit glob *.{a,b,}test verwenden

Ich möchte alle Dateien in einem Ordner namens auflisten, die foldernamedie Erweiterung testoder haben .atestbtest

Mein erster Gedanke war wegzurennenls ./foldername/*.{a,b,}test

Das funktioniert einwandfrei, sofern mit der Erweiterung nichts übereinstimmt atest. In diesem Fall erhalte ich die Fehlermeldung zsh: no matches found: ./foldername/*.atest.

Gibt es eine Möglichkeit, diesen Fehler einfach zu ignorieren und die vorhandenen Dateien auszudrucken?

Ich brauche, dass dies sowohl in zsh als auch in Bash funktioniert.

Antwort1

In

ls -d ./foldername/*.{a,b,}test

{a,b,...}ist kein Glob-Operator, das ist eine Klammererweiterung, die zuerst wie folgt erweitert wird:

ls -d ./foldername/*.atest ./foldername/*.btest ./foldername/*.test

Und jeder Glob wird einzeln erweitert, und wenn ein Glob nicht übereinstimmt, wird der Befehl wie erwartet in abgebrochen zsh(oder fish; in bashbenötigen Sie die failglobOption, um ein ähnliches Verhalten zu erhalten).

Hier sollten Sie einen einzelnen Glob verwenden, der mit all diesen Dateien übereinstimmt, und den Befehl nur abbrechen, wenn dieser eine Glob mit keiner Datei übereinstimmt:

ls -d ./foldername/*.(a|b|)test

Sie möchten nicht verwenden nullglob, da es ohne Argumente ausgeführt würde, wenn keiner der Globs übereinstimmt. lsListen Sie daher das aktuelle Verzeichnis auf. cshnullglobist in dieser Hinsicht besser, da es nicht übereinstimmende Globs entfernt, den Befehl jedoch abbricht, wenn keine der Globs übereinstimmt.

Sie sollten nicht verwenden nonomatch, da dies zu fehlerhaftem Verhalten führen würde, bashwas schade wäre.

Für eine Glob-Alternative, die sowohl in zshals auch funktioniert, können Sie die Ksh-Globs ( in und in ) bashverwenden .set -o kshglobzshshopt -s extglobbash

Dann würden Sie Folgendes tun:

ls -d ./foldername/*.@(a|b|)test

oder:

ls -d ./foldername/*.?([ab])test

Fügen Sie die failglobOption hinzu, bashum zu verhindern, dass der Glob wörtlich übergeben wird, lswenn er nicht übereinstimmt.

SehenWarum ist Nullglob nicht Standard?für mehr Informationen.

Antwort2

Dies geht möglicherweise am besten mit find:

find ./foldername -maxdepth 1 -name '*.atest' -o -name '*.btest' -o -name '*.test'

Antwort3

Ich stand vor diesem Problem und löste es zunächst, indem ich ls selbst hackte. Als ich fertig war, erkannte ich, dass ich nur das trivale C-Programm brauchte:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
  struct stat statbuf;
  int i;
  for( i=1; i<argc; i++ ) {
    if( stat(argv[i],&statbuf) == 0 ) {
      printf("%s\n",argv[i]);
    }
  }
}

Dies führt lediglich die Befehlszeilenargumente aus und gibt die Zeichenfolgen aus, die gültigen Dateien entsprechen (d. h. für die stat() erfolgreich ist), und das ist auch alles, was es tun muss.

Natürlich können wir dies mit ebenso einfachem Python, Perl oder sogar einer Shell-Funktion emulieren, die stat ausführt, aber wenn man es in C schreibt, läuft es viel schneller.

Was das Hacken von ls betrifft, habe ich in meinem persönlichen Wiki einen Durchlauf durchgeführt:http://linux.chalisque.net/LsIgnoreMissing

Antwort4

Der Kommentar von @DopeGhoti hat bei mir funktioniert.

d. h. den Fehler umleiten, indem man einen Operator wie folgt /dev/nullverwendet :2>

ls ./foldername/*.{a,b,}test 2> /dev/null

verwandte Informationen