Edit:
Important note before reading further: since Kusalananda's anwser, my question is now quite useless, since he pointed out a bug in another script I used. Now this bug is fixed, the below errors I described no longer occur!
There are two issues in your code which causes the value in $extension to be expanded
The second issue is the function itself
TL;DR
I was stuck when I started writing the question, but found a solution that works (using shell noglob), BUT I still have a question of "would it be possible to write".
I'm sure this has already been answered, but I get lost in hundreds of topics about bash expansion.
Here is my case:
- I want to run a script (lets say
ffmpeg
with option-pattern_type glob -i
mode that accepts a regexp like*.JPG
) - taking an argument (lets say
*.JPG
) - argument coming from a variable (lets say
$extension
) - variable coming from script parameters (lets say
$1
) - but I do not want shell to expand
$extension
as by default for a pattern like*.JPG
Note that all this actions take place in a script script.sh
.
Thus, the user could run:
script.sh 'JPG' ; # where $1='JPG'
Note: in script.sh
, I concatenate *.
and $1
to get a more final regexp like *.JPG
I read (from here https://stackoverflow.com/a/11456496/912046) that shell expansion occurs before ffmpeg
receives arguments (ffmpeg
even does not know Shell expansion took place)
I tried to play with quotes, double quotes, or backslashes around ${extension}
in different ways, unsuccessfully.
Here are some tries:
ffmpeg ... "${extension}"
leads to: ffmpeg 1.jpg 2.jpg [...]
(expansion occurs)
ffmpeg ... ${extension}
same
ffmpeg ... '${extension}'
leads to no file match because of searching pattern ${extension}
(variable name is used literally)
extension="\'${extension}\'" ; # wrapping the single quotes (preventing expansion) directly in variable
ffmpeg ... ${extension}
leads to no file match because of searching pattern '*.jpg'
(including single quotes)
ffmpeg ... \"${extension}\"
same but searching for "*.jpg"
(including double quotes)
I finally succeeded using Shell noglob option.
Here is the command for curious:
set -f ; # disable glob (prevent expansion on '*.jpg')
ffmpeg -pattern_type glob -i ${extension} movie.mp4 ;
set +f ; # restore, but what if glob was already disabled? I should not restore it then?
But for my curiosity, is there another way of preventing expansion on a script argument coming from a variable we WANT to be resolved? (thus, the way I know of preventing expansion (using single quotes) makes variable no longer resolved/replaced).
Something like : (but I read string concatenation should be avoided for safety, injection)
ffmpeg '${extension}'
|| | 3
|| 2
| 1
where :
- 1: would open single quote for final result being
ffmpeg '*.jpg'
- 2: would inject and resolve our variable
extension
to.jpg
- 3: would close single quote for
ffmpeg
to receive argument as if I manually had written'*.jpg'
Edit: after comment about how extension variable is assigned:
local extension="${2}" ;
echo $extension ;
extension="${extension:=jpg}" ; # Default on "jpg" extension
# wrapp extension type in single quotes + prefix with "*."
extension="*.${extension}" ;
Then, using it with:
runprintcommand ffmpeg -loglevel verbose -pattern_type glob -i ${extension} "$movieName" ;
Where the runprintcommand
function/script being:
function runprintcommand() {
echo "Command to run: (Note: '\\' escape character may not be printed)" ;
echo "$*" ;
$* ;
}
"$extension"
(or"${extension}"
) would expand the variable, but would under no circumstances perform filename globbing on the result, unless you usedeval
on the result of the expansion. You are doing something very strange if it did that. Or,ffmpeg
might possibly do its own globbing, which it would do regardless ofset -f
in that case. Show us how you assign toextension
to create it from$1
.ffmpeg
to a custom homemade, possibly brokenrunprintcommand
function, which may interfer with globbing.extension
variable's value.