If your shell is the latest version of bash enough, then the parameter extension should work.
In many other shells this will not work, and the bad substitution error is how the shell says: "You asked to replace the parameter, but that does not make sense to me."
Also, given the script:
#! /bin/sh length=echo `expr index "$1" .zip` a=$1 echo $(a:0:length}
The second line exports the length variable with the echo value for the command that is created when expr index "$1" .zip is run. It does not assign length . This should be fair:
length=$(expr index "${1:?}" .zip)
where the notation ${1:?} generates an error if $1 not specified (if the script is called without arguments).
The last line should be:
echo ${a:0:$length}
Note that if $1 contains filename.zip , the output of expr index $1 .zip is 2, since the letter i appears at index 2 in filename.zip . If the goal is to get the base file name without the .zip extension, then the classic way to do this is:
base=$(basename $1 .zip)
and more modern way:
base=${1%.zip}
There is a difference; if the name is /path/to/filename.zip , the classic output is filename , and modern is /path/to/filename . You can get classic output with:
base=${1%.zip} base=${base##*/}
Or, in the classic version, you can get the path with:
base=$(dirname $1)/$(basename $1 .zip)`.)
If file names may contain spaces, you need to consider using double quotes, especially in calls to basename and dirname .