Podstawienie Bash zmienną zdefiniowaną na podstawie wzorca globu

10

Poniższy przykład wyjaśnia problem. Dlaczego jest FILENAMEdrukowany poprawnie, gdy odbija się echem i jest postrzegany jako wzór przy stosowaniu zastępczym?

#!/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
źródło

Odpowiedzi:

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

Teraz FILEPATH_WITH_GLOBzawiera/home/user/file_*

FILENAME=$(basename "$FILEPATH_WITH_GLOB")

FILENAMEzawiera file_*.

echo $FILENAME                #file_1234

$FILENAMEponieważ nie jest cytowany w kontekście listy, to rozwinięcie podlega operatorowi split + glob, więc zostaje ono rozszerzone na listę pasujących plików: generowanie nazw plików następuje po rozwinięciu parametrów .

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

Jest to wciąż niecytowane rozszerzenie parametrów w kontekście listy, więc nadal podlega podziałowi + glob. Jednak tutaj ile_*wzorzec nie pasuje do żadnego pliku, więc zamiast tego rozwija się do siebie.

Prawdopodobnie chcesz tutaj:

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

Lub możesz przechowywać je w tablicy:

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

Jeśli zależy Ci tylko na pierwszym dopasowaniu lub wiesz, że istnieje tylko jedno dopasowanie, możesz odnieść się do tego pliku jako $files. bashma to zwykle denerwujące zachowanie, które $filesrozwija się ${files[0]}zamiast wszystkich elementów tablicy (zachowanie odziedziczone ksh, ustalone w zsh), ale tutaj byłoby to zachowanie pożądane raz.

Stéphane Chazelas
źródło
Dziękuję za wyjaśnienie. Udało się zrobić obejście FILEPATH_WITH_GLOB=`echo /home/user/file_*` po wyjaśnieniu.
TheMeaningfulEngineer
@Alan, to zły sposób na rozwiązanie tego problemu. Chcesz użyć tablicy tutaj. Albo parametry pozycyjne jak w moim przykładzie ($ 1, $ 2 ...) lub bashtablica jak: files=(/home/user/file_*).
Stéphane Chazelas,
(i wszystkie zmienne pisane wielkimi literami powinny być naprawdę zarezerwowane dla zmiennych środowiskowych, echonie powinny być używane do dowolnych danych , zmiennych nie należy pozostawiać bez cudzysłowów w kontekście list).
Stéphane Chazelas,