Ignore "no hay coincidencias" de zsh cuando utilice la expansión de llaves con glob *.{a,b,}test

Ignore "no hay coincidencias" de zsh cuando utilice la expansión de llaves con glob *.{a,b,}test

Me gustaría enumerar todos los archivos en una carpeta llamada que foldernametiene la extensión testo atest.btest

Mi pensamiento inmediato fue correrls ./foldername/*.{a,b,}test

Esto funciona bien a menos que no haya nada con la extensión atest, en cuyo caso aparece el error zsh: no matches found: ./foldername/*.atest.

¿Hay alguna manera de ignorar este error e imprimir los archivos que existen?

Necesito que esto funcione tanto en zsh como en Bash.

Respuesta1

En

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

{a,b,...}no es un operador global, eso es una expansión de llaves, que primero se expande a:

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

Y cada globo se expandió individualmente, y si algún globo no coincide, el comando se cancela como era de esperar en zsh(o fish; en bash, necesita la failglobopción para obtener un comportamiento similar).

Aquí, querrás usar un solo globo que coincida con todos esos archivos y solo cancelar el comando si ese globo no coincide con ningún archivo:

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

No desea utilizar nullglob, ya que si ninguno de los globos coincidiera, se ejecutaría lssin argumentos, así que indique el directorio actual. cshnullglobes mejor en ese sentido, ya que elimina los globos que no coinciden pero aun así cancela el comando si todos los globos no coinciden.

No querrás usarlo nonomatch, ya que eso te daría un comportamiento roto, bashlo cual sería una pena.

Para obtener una alternativa global que funcione tanto en zshcomo en bash, puede usar ksh globs ( set -o kshglobin zshy shopt -s extglobin bash).

Entonces, harías:

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

o:

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

Agregue la failglobopción bashpara evitar que el globo se pase literalmente lscuando no coincida.

Ver¿Por qué nullglob no es el predeterminado?para más información.

Respuesta2

Quizás sea mejor hacer esto con find:

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

Respuesta3

Me enfrenté a este problema y primero lo resolví pirateando el propio ls. Cuando terminé, me di cuenta de que todo lo que necesitaba era el programa trival C:

#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]);
    }
  }
}

Todo lo que esto hace, y todo lo que necesita hacer, es ejecutar los argumentos de su línea de comando y repetir aquellas cadenas que corresponden a archivos válidos (es decir, para los cuales stat() tiene éxito).

Por supuesto, podemos emular esto con Python, Perl o incluso una función de shell que ejecute stat, igualmente simple, pero escribirlo en C hace que su ejecución sea mucho más rápida.

En cuanto a piratear ls, lo revisé en mi wiki personal:http://linux.chalisque.net/LsIgnoreMissing

Respuesta4

El comentario de @DopeGhoti funcionó para mí.

es decir, redirigir el error al /dev/nulluso 2>del operador de esta manera:

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

información relacionada