Substituição de bash com variável definida a partir de um padrão glob

10

O exemplo abaixo explica o problema. Por que a FILENAMEimpressão é correta quando ecoada e percebida como padrão ao usar a substituição?

#!/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
TheMeaningfulEngineer
fonte

Respostas:

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

Agora, FILEPATH_WITH_GLOBcontém/home/user/file_*

FILENAME=$(basename "$FILEPATH_WITH_GLOB")

FILENAMEcontém file_*.

echo $FILENAME                #file_1234

$FILENAMEsendo não citado no contexto da lista, essa expansão passa pelo operador split + glob, sendo expandida para a lista de arquivos correspondentes: a geração do nome do arquivo é realizada na expansão do parâmetro .

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

Ainda é uma expansão de parâmetro sem aspas no contexto da lista, e ainda sofre divisão + glob. No entanto, aqui, o ile_*padrão não corresponde a nenhum arquivo; portanto, ele se expande para si mesmo.

O que você provavelmente quer aqui é:

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

Ou você pode armazená-los em uma matriz:

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

Se você se importa apenas com a primeira correspondência ou sabe que há apenas uma correspondência, pode consultar esse arquivo como $files. bashtem esse comportamento geralmente irritante que se $filesexpande para em ${files[0]}vez de todos os elementos da matriz (um comportamento herdado de ksh, fixado em zsh), mas aqui, esse seria um comportamento desejado pela primeira vez.

Stéphane Chazelas
fonte
Obrigada pelo esclarecimento. Conseguiu fazer uma solução alternativa FILEPATH_WITH_GLOB=`echo /home/user/file_*` após sua explicação.
TheMeaningfulEngineer
@ Alan, essa é a maneira errada de lidar com isso. Você deseja usar uma matriz aqui. Ou os parâmetros posicionais como no meu exemplo ($ 1, $ 2 ...) ou uma bashmatriz como: files=(/home/user/file_*).
Stéphane Chazelas
(e todas as variáveis ​​em maiúsculas devem ser realmente reservadas para variáveis ​​de ambiente, echonão devem ser usadas para dados arbitrários , as variáveis ​​não devem ser deixadas sem aspas em contextos de lista).
Stéphane Chazelas