Bash substitution with variable defined from a glob pattern
FILEPATH_WITH_GLOB="/home/user/file_*"
Now, FILEPATH_WITH_GLOB
contains /home/user/file_*
FILENAME=$(basename "$FILEPATH_WITH_GLOB")
FILENAME
contains file_*
.
echo $FILENAME #file_1234
$FILENAME
being unquoted in list context, that expansion undergoes the split+glob operator, so that's expanded to the list of matching file: filename generation is performed upon parameter expansion.
echo ${FILENAME:1:5} #ile_* <---why is this not ile_1
It's still an unquoted parameter expansion in list context, so still undergoes split+glob. However here, the ile_*
pattern doesn't match any file, so it expands to itself instead.
What you probably want here is:
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
Or you can store them in an array:
shopt -s nullglob
files=(/home/user/file_*)
If you only care about the first match, or you know there's only one match, you can then refer to that file as $files
. bash
has that usually annoying behaviour that $files
expands to ${files[0]}
instead of all the elements of the array (a behaviour inherited from ksh
, fixed in zsh
), but here, that would be a wanted behaviour for once.
Related videos on Youtube
![TheMeaningfulEngineer](https://i.stack.imgur.com/mE5HL.png?s=256&g=1)
TheMeaningfulEngineer
I like to think of myself as a Hardware/Software guy who will gladly discuss referential transparency during a code review and the next moment take a circular saw to build a casing for a self made power supply. My main interest can be summarized into Linux related software development, low power electronics and general DIY projects.
Updated on September 18, 2022Comments
-
TheMeaningfulEngineer almost 2 years
The below example explains the issue. Why is the
FILENAME
printed correctly when echoed and perceived as a pattern when using 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
-
Stéphane Chazelas about 9 years@Alan, that's the wrong way to address it. You want to use a array here. Either the positional parameters as in my example ($1, $2...) or a
bash
array like:files=(/home/user/file_*)
. -
Stéphane Chazelas about 9 years(and all upper-case variables should really be reserved for environment variables,
echo
should not be used for arbitrary data, variables should not be left unquoted in list contexts).