Tengo el siguiente script bash simplificado
#!/bin/bash
files=("$@")
if [ "X$files" = "X" ]; then
files=$HOME/print/*.pdf;
fi
for file in "${files[@]}"; do
ls "$file";
done
Si paso argumentos (nombres de archivo) como parámetros, este script imprimirá los nombres de archivo adecuados. Por otro lado, si no paso argumentos, imprimirá
/home/user/print/*.pdf: No such file or directory
¿Por qué los nombres de archivo no se expanden en este caso y cómo lo soluciono? Tenga en cuenta que uso las construcciones files=("$@")y "${files[@]}"porque leí que es preferible a los "archivos = $ *" habituales.

files=$*siempre usual ? Eso está completamente mal .Respuestas:
Estás asignando
filescomo una variable escalar en lugar de una variable de matriz .En
Estás asignando una cadena similar
/home/highsciguy/print/*.pdfa la$filesvariable escalar (también conocida como cadena).Utilizar:
o
en lugar. El shell expandirá ese patrón global en una lista de rutas de archivo y asignará cada una de ellas a los elementos de la
$filesmatriz .La expansión del globo se realiza en el momento de la asignación.
No tiene que usar funciones sh no estándar, y puede usar las de su sistema en
shlugar debashaquí escribiéndolas:setes asignar la"$@"matriz de parámetros posicionales.Otro enfoque podría haber sido almacenar el patrón globbing en una variable escalar:
Y haga que el shell expanda el glob en el momento en
$filesque se expande la variable.Aquí, debido a
$filesque no se cita (lo que normalmente no se debe hacer), su expansión está sujeta a la división de palabras (que hemos desactivado aquí) y la generación de nombres de archivo / globbing.Por lo tanto
*.pdf, se expandirá a la lista de archivos coincidentes. Sin embargo, si$HOMEcontuviera caracteres comodín, también podrían expandirse, por lo que todavía es preferible usar una variable de matriz.fuente
Es posible que haya visto cosas como
files=$*yfiles=~/print/*.pdfen conchas antiguas sin matrices, y luegols $files.Una sustitución de variable que no está entre comillas dobles interpreta el valor de la variable como una lista separada por espacios en blanco de patrones comodín de shell que se reemplazan por nombres de archivo coincidentes, si los hay. Por ejemplo, después
files=~/print/*.pdf, sels $filesexpande a algo así comolscon los argumentos/home/highsciguy/print/bar.pdf,/home/highsciguy/print/foo.pdfetc. En el casofiles=$*, esta asignación concatena los argumentos pasados al script con espacios en el medio y losls $filesdivide de nuevo.Todo esto se descompone si tiene nombres de archivo que contienen espacios en blanco o caracteres globales, por lo que no debe hacer las cosas de esta manera. Utilice matrices en su lugar.
Tenga en cuenta que
var=(…)."$files"está vacío cuandofileses una matriz cuyo elemento del índice 0 no está establecido o una cadena vacía. También[ "X$foo" = "X" ]es una forma obsoleta de probar si$fooestá vacía: todos los shells modernos se implementan[ -n "$foo" ]correctamente. En bash, puedes usar[[ -n $foo ]].En los shells que no admiten arrays, de hecho hay un array: los parámetros posicionales para el shell o la función actual. Aquí, realmente no necesita la
filesmatriz, de hecho, sería más fácil usar los parámetros posicionales.fuente