Substitution de Bash avec variable définie à partir d'un modèle global

10

L'exemple ci-dessous explique le problème. Pourquoi l' FILENAMEimpression est-elle correctement lorsqu'elle est répétée et perçue comme un motif lors de l'utilisation de la substitution?

#!/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
la source

Réponses:

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

Maintenant, FILEPATH_WITH_GLOBcontient/home/user/file_*

FILENAME=$(basename "$FILEPATH_WITH_GLOB")

FILENAMEcontient file_*.

echo $FILENAME                #file_1234

$FILENAMEétant non cité dans le contexte de la liste, cette expansion subit l'opérateur split + glob, de sorte qu'elle est étendue à la liste des fichiers correspondants: la génération du nom de fichier est effectuée lors de l' expansion des paramètres .

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

Il s'agit toujours d'une extension de paramètre non citée dans le contexte de la liste, donc subit toujours split + glob. Cependant, ici, le ile_*modèle ne correspond à aucun fichier, il se développe donc à lui-même.

Ce que vous voulez probablement ici, c'est:

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 vous pouvez les stocker dans un tableau:

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

Si vous ne vous souciez que de la première correspondance ou si vous savez qu'il n'y a qu'une seule correspondance, vous pouvez alors faire référence à ce fichier en tant que $files. basha ce comportement généralement ennuyeux qui se $filesdéveloppe à la ${files[0]}place de tous les éléments du tableau (un comportement hérité de ksh, fixé dans zsh), mais ici, ce serait un comportement souhaité pour une fois.

Stéphane Chazelas
la source
Merci pour l'explication. J'ai réussi à contourner ce problème FILEPATH_WITH_GLOB=`echo /home/user/file_*` après votre explication.
TheMeaningfulEngineer
@Alan, c'est la mauvaise façon d'y remédier. Vous souhaitez utiliser un tableau ici. Soit les paramètres de position comme dans mon exemple (1 $, 2 $ ...) ou un bashtableau comme: files=(/home/user/file_*).
Stéphane Chazelas
(et toutes les variables majuscules doivent vraiment être réservées aux variables d'environnement, echone doivent pas être utilisées pour des données arbitraires , les variables ne doivent pas être laissées sans guillemets dans les contextes de liste).
Stéphane Chazelas