23

I'm new to shell programming. I intend to get directory name after zip file was extracted. The print statement of it is

$test.sh helloworld.zip
helloworld

Let's take a look at test.sh:

#! /bin/sh
length=echo `expr index "$1" .zip`
a=$1    
echo $(a:0:length}

However I got the Bad substitution error from the compiler.

And when I mention about 'shell'.I just talking about shell for I don't know the difference between bash or the others.I just using Ubuntu 10.04 and using the terminal. (I am using bash.)

abunickabhi
  • 558
  • 2
  • 9
  • 31
cattail
  • 337
  • 1
  • 3
  • 9
  • what is your argument to the script, i.e. the value of $1? Please edit this information INTO your message above, and not as a reply to my comment. try surrounding all references to $1 in dbl-quotes, i.e. `echo "$1"`, etc. Good luck! – shellter Oct 11 '12 at 03:39
  • What did you expext with `${a:0}` ? – Gilles Quénot Oct 11 '12 at 03:40
  • 2
    try changing the first line to `#!/bin/bash`. Good luck. – shellter Oct 11 '12 at 03:52
  • Wow,add #! /bin/bash works.WHY?What's the difference between using #! /bin/bash and #! /bin/sh – cattail Oct 11 '12 at 03:56
  • They are different shells that implement different features. Even if `/bin/sh` is bash, it is executed as if `--posix` was used, which disables some bash features. – jordanm Oct 11 '12 at 03:59
  • If you're on Ubuntu, `/bin/sh` may be `dash` (Debian Almquist Shell), and that hews to the POSIX standard very closely, and doesn't support Bash-only extensions. – Jonathan Leffler Mar 25 '14 at 16:46

3 Answers3

19

If your shell is a sufficiently recent version of bash, that parameter expansion notation should work.

In many other shells, it will not work, and a bad substitution error is the way the shell says 'You asked for a parameter substitution but it 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 variable length with value echo for the command that is generated by running expr index "$1" .zip. It does not assign to length. That should be just:

length=$(expr index "${1:?}" .zip)

where the ${1:?} notation generates an error if $1 is not set (if the script is invoked with no arguments).

The last line should be:

echo ${a:0:$length}

Note that if $1 holds filename.zip, the output of expr index $1 .zip is 2, because the letter i appears at index 2 in filename.zip. If the intention is to get the base name of the file without the .zip extension, then the classic way to do it is:

base=$(basename $1 .zip)

and the more modern way is:

base=${1%.zip}

There is a difference; if the name is /path/to/filename.zip, the classic output is filename and the modern one is /path/to/filename. You can get the 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 the file names can contain spaces, you need to think about using double quotes, especially in the invocations of basename and dirname.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    What is a "sufficiently recent version" ? I'm working with bash 4.2.37 and I'm facing this problem. – Simon Mar 25 '14 at 16:17
  • @Simon: it works for me with Bash 3.2.51 (provided with Mac OS X 10.9.2 Mavericks). It also works with Bash 4.2.25 (provided with Ubuntu 12.04). For example: `AZ=abcdefghijklmnopqrstuvwxyz; echo ${AZ:10:10}` yields `klmnopqrst` on both systems. Further, it works OK whether it is Bash run as `bash` or as `sh`. So, you'd need to elaborate on exactly what you're doing, along the lines of the example I've just given. Note that both values must be numbers. You could write: `length=10` and `echo ${AZ:10:$length}` but the second `$` is crucial in that notation. – Jonathan Leffler Mar 25 '14 at 16:29
  • Thanks for the fast answer. Actually `AZ=abcdefghijklmnopqrstuvwxyz; echo ${AZ:10:10}` yields a `Bad substitution` for me (Bash 4.2.37 - Debian 7.4). I guess I have to dig deeper. – Simon Mar 25 '14 at 17:21
  • 1
    @Simon: now that is a curious state of affairs. I guess you're going to need to track down what is in 4.2.37 vs 4.2.25, or something (with no guarantee that your '.25' is the same as 'mine'). [Bash 4.3](ftp://ftp.gnu.org/gnu/bash/) was released by Gnu 2014-02-26 (4.2 on 2011-02-13). Maybe try building that? Otherwise, you may have a regression bug on your hands. (I just built Bash 4.3 on Mac OS X 10.9.2 while adding this comment — it took a couple of minutes after completing the download — and the AZ-test works cleanly on it.) – Jonathan Leffler Mar 25 '14 at 17:40
  • @Simon — it occurs to me five years later that you may be (have been) using `dash` instead of `bash`. – Jonathan Leffler Apr 13 '19 at 17:51
9

Try running it with bash.

bash test.sh helloworld.zip

-likewise-

"try changing the first line to #!/bin/bash" as comment-answered by – @shellter

Brian Davis
  • 345
  • 4
  • 9
1

Try that in bash :

echo $1
len=$(wc -c <<< "$1")
a="${1}.zip"
echo ${a:0:$len}

Adapt it to fit your needs.

Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223