Bash-Substitution mit einer aus einem Glob-Muster definierten Variablen

10

Das folgende Beispiel erläutert das Problem. Warum wird der FILENAMEAusdruck korrekt gedruckt, wenn er bei Verwendung der Substitution als Muster wiedergegeben und wahrgenommen wird?

#!/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
quelle

Antworten:

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

Jetzt FILEPATH_WITH_GLOBenthält/home/user/file_*

FILENAME=$(basename "$FILEPATH_WITH_GLOB")

FILENAMEenthält file_*.

echo $FILENAME                #file_1234

$FILENAMEDa diese Erweiterung im Listenkontext nicht in Anführungszeichen gesetzt ist, wird sie dem Operator split + glob unterzogen, sodass sie auf die Liste der übereinstimmenden Dateien erweitert wird: Die Generierung des Dateinamens erfolgt bei der Parametererweiterung .

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

Es handelt sich immer noch um eine nicht zitierte Parametererweiterung im Listenkontext, daher wird immer noch split + glob durchgeführt. Hier ile_*stimmt das Muster jedoch nicht mit einer Datei überein, sodass es stattdessen auf sich selbst erweitert wird.

Was Sie hier wahrscheinlich wollen, ist:

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

Oder Sie können sie in einem Array speichern:

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

Wenn Sie sich nur für die erste Übereinstimmung interessieren oder wissen, dass es nur eine Übereinstimmung gibt, können Sie auf diese Datei als verweisen $files. bashhat das normalerweise nervige Verhalten, das $filessich auf ${files[0]}alle Elemente des Arrays ausdehnt (ein Verhalten, das von geerbt kshund behoben wurde zsh), aber hier wäre das einmal ein gewünschtes Verhalten.

Stéphane Chazelas
quelle
Danke für die Erklärung. Hat es geschafft, FILEPATH_WITH_GLOB=`echo /home/user/file_*` nach Ihrer Erklärung eine Problemumgehung durchzuführen.
TheMeaningfulEngineer
@ Alan, das ist der falsche Weg, um es anzusprechen. Sie möchten hier ein Array verwenden. Entweder die Positionsparameter wie in meinem Beispiel ($ 1, $ 2 ...) oder ein bashArray wie : files=(/home/user/file_*).
Stéphane Chazelas
(und alle Variablen in Großbuchstaben sollten wirklich für Umgebungsvariablen reserviert sein, echosollten nicht für beliebige Daten verwendet werden , Variablen sollten in Listenkontexten nicht unzitiert bleiben).
Stéphane Chazelas