Ich möchte alle Dateien in einem Ordner namens auflisten, die foldername
die Erweiterung test
oder haben .atest
btest
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 bash
benötigen Sie die failglob
Option, 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. ls
Listen Sie daher das aktuelle Verzeichnis auf. cshnullglob
ist 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, bash
was schade wäre.
Für eine Glob-Alternative, die sowohl in zsh
als auch funktioniert, können Sie die Ksh-Globs ( in und in ) bash
verwenden .set -o kshglob
zsh
shopt -s extglob
bash
Dann würden Sie Folgendes tun:
ls -d ./foldername/*.@(a|b|)test
oder:
ls -d ./foldername/*.?([ab])test
Fügen Sie die failglob
Option hinzu, bash
um zu verhindern, dass der Glob wörtlich übergeben wird, ls
wenn 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/null
verwendet :2>
ls ./foldername/*.{a,b,}test 2> /dev/null