26

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.)

6
  • 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! Commented Oct 11, 2012 at 3:39
  • What did you expext with ${a:0} ? Commented Oct 11, 2012 at 3:40
  • 2
    try changing the first line to #!/bin/bash. Good luck. Commented Oct 11, 2012 at 3:52
  • Wow,add #! /bin/bash works.WHY?What's the difference between using #! /bin/bash and #! /bin/sh Commented Oct 11, 2012 at 3: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. Commented Oct 11, 2012 at 3:59

3 Answers 3

21

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.

Sign up to request clarification or add additional context in comments.

8 Comments

What is a "sufficiently recent version" ? I'm working with bash 4.2.37 and I'm facing this problem.
@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.
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: 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 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.)
@Simon — it occurs to me five years later that you may be (have been) using dash instead of bash.
|
10

Try running it with bash.

bash test.sh helloworld.zip

-likewise-

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

1 Comment

i was using sh test.sh and updated bash test.sh. Thanks
1

Try that in bash :

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

Adapt it to fit your needs.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.