Sustitución de bash con variable definida a partir de un patrón global

10

El siguiente ejemplo explica el problema. ¿Por qué se FILENAMEimprime correctamente cuando se repite y se percibe como un patrón cuando se usa la sustitución?

#!/bin/bash

FILEPATH_WITH_GLOB="/home/user/file_*"
FILENAME=$(basename "$FILEPATH_WITH_GLOB")
echo $FILENAME                #file_1234
echo ${FILENAME:1:5}          #ile_*   <---why is this not ile_1
El Ingeniero Significante
fuente

Respuestas:

15
FILEPATH_WITH_GLOB="/home/user/file_*"

Ahora FILEPATH_WITH_GLOBcontiene/home/user/file_*

FILENAME=$(basename "$FILEPATH_WITH_GLOB")

FILENAMEcontiene file_*.

echo $FILENAME                #file_1234

$FILENAMEal no estar entre comillas en el contexto de la lista, esa expansión se somete al operador split + glob, por lo que se expande a la lista de archivos coincidentes: la generación del nombre de archivo se realiza al expandir los parámetros .

echo ${FILENAME:1:5}          #ile_*   <---why is this not ile_1

Sigue siendo una expansión de parámetros sin comillas en el contexto de la lista, por lo que aún se divide + glob. Sin embargo, aquí, el ile_*patrón no coincide con ningún archivo, por lo que se expande a sí mismo.

Lo que probablemente quieras aquí es:

shopt -s nullglob # have globs expand to nothing when they don't match
set -- /home/user/file_* # expand that pattern into the list of matching 
                         # files in $1, $2...
for file do  # loop over them
  filename=$(basename -- "$file")
  printf '%s\n' "$filename" "${filename:1:5}"
done

O puede almacenarlos en una matriz:

shopt -s nullglob
files=(/home/user/file_*)

Si solo le importa la primera coincidencia, o sabe que solo hay una coincidencia, puede referirse a ese archivo como $files. bashtiene ese comportamiento generalmente molesto que se $filesexpande en ${files[0]}lugar de todos los elementos de la matriz (un comportamiento heredado de ksh, arreglado zsh), pero aquí, ese sería un comportamiento deseado por una vez.

Stéphane Chazelas
fuente
Gracias por la explicación. Se las arregló para hacer una solución alternativa FILEPATH_WITH_GLOB=`echo /home/user/file_*` después de su explicación.
TheMeaningfulEngineer
@ Alan, esa es la forma incorrecta de abordarlo. Desea usar una matriz aquí. Cualquiera de los parámetros posicionales como en mi ejemplo ($ 1, $ 2 ...) o una bashmatriz como: files=(/home/user/file_*).
Stéphane Chazelas
(y todas las variables en mayúsculas realmente deberían reservarse para las variables de entorno, echono deberían usarse para datos arbitrarios , las variables no deberían dejarse sin comillas en contextos de lista).
Stéphane Chazelas