Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Bash Scripting Error: Bad substitution

695 views
Skip to first unread message

rupert

unread,
Jan 3, 2009, 7:25:57 AM1/3/09
to
I've been going through a very good bash scripting tutorial here:
http://tldp.org/LDP/abs/html/parameter-substitution.html#PSUB2

It is based on the Korne-shell (so naturally the she-bang is: #!/bin/
ksh)
but I want to continue to program in my Borne-again-shell with #!/bin/
bash
(or #!/bin/sh as I gather ubuntu 8.10 is bash by default).

#!/bin/bash
#this causes a Bad substitution error...
path_name=/home/bozo/ideas/somestuff
t=${path_name/bozo/clown} #this will fail here...
echo $t
exit 0

what is the Bash alternative to do a substitution like this?

Bit Twister

unread,
Jan 3, 2009, 7:58:05 AM1/3/09
to
On Sat, 3 Jan 2009 04:25:57 -0800 (PST), rupert wrote:

> path_name=/home/bozo/ideas/somestuff
> t=${path_name/bozo/clown} #this will fail here...

t=${path_name}/bozo/clown

Martin Vaeth

unread,
Jan 3, 2009, 11:09:10 AM1/3/09
to
rupert <rup...@web-ideas.com.au> wrote:
>
> #!/bin/bash
> #this causes a Bad substitution error...
> path_name=/home/bozo/ideas/somestuff
> t=${path_name/bozo/clown} #this will fail here...
> echo $t
> exit 0
>
> what is the Bash alternative to do a substitution like this?

Your question seems strange, because bash (at least if called with
/bin/bash, I tested with 3.2.48) has no problems with this code.
I guess you mean "what is the dash/POSIX alternative?"
Unfortunately, there is none. You must program it manually using
something like
t=${path_name##bozo*}clown${path_name%*bozo}

Jasen Betts

unread,
Jan 3, 2009, 1:46:15 PM1/3/09
to
On 2009-01-03, rupert <rup...@web-ideas.com.au> wrote:
> I've been going through a very good bash scripting tutorial here:
> http://tldp.org/LDP/abs/html/parameter-substitution.html#PSUB2
>
> It is based on the Korne-shell (so naturally the she-bang is: #!/bin/
> ksh)
> but I want to continue to program in my Borne-again-shell with #!/bin/
> bash
> (or #!/bin/sh as I gather ubuntu 8.10 is bash by default).

Don't. sh could be any posix compatible shell, if you want to use bash
featrures specify bash.

> #!/bin/bash
> #this causes a Bad substitution error...
> path_name=/home/bozo/ideas/somestuff
> t=${path_name/bozo/clown} #this will fail here...
> echo $t
> exit 0

that works here,
xxx$ ./testscript
/home/clown/ideas/somestuff
xxx$

John Hasler

unread,
Jan 3, 2009, 2:18:11 PM1/3/09
to
rupert writes:
> but I want to continue to program in my Borne-again-shell with #!/bin/
> bash (or #!/bin/sh as I gather ubuntu 8.10 is bash by default).

When Bash is called as "sh" it tries to be POSIX-compatible and so disables
many extensions. If you want to use Bash features use Bash and call it as
"bash".
--
John Hasler
jo...@dhh.gt.org
Dancing Horse Hill
Elmwood, WI USA

noi ance

unread,
Jan 3, 2009, 2:53:44 PM1/3/09
to
On Sat, 03 Jan 2009 04:25:57 -0800, rupert typed this message:

t=$path_name/bozo/clown

rupert

unread,
Jan 3, 2009, 5:04:18 PM1/3/09
to

Thanks for you assistance unfortunately although this can be
interpreted it does not give the desired result.
I want to achieve: /home/clown/ideas/somestuff not /home/bozo/ideas/
somestuff/bozo/clown

rupert

unread,
Jan 3, 2009, 5:16:39 PM1/3/09
to

Interesting, I'm starting to understand this a little better...
now the following works fine:

#/bin/bash
stringZ=abcABC123ABCabc
echo ${stringZ/abc/xyz} # xyzABC123ABCabc
echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
exit 0

but only when the following line is called:
username$ bash filename.sh

the following does not work:
username$ chmod 744 filename.sh
username$ ./filename.sh

malloc: ../bash/dispose_cmd.c:241: assertion botched
free: called with unallocated block argument
Aborting...Aborted

it seems a call to bash is interpreted as "bash"
but a ./filename.sh with a shebang of #!/bin/bash is not.

or is this what John Hasler below is referring to by POSIX-compatible?
ie ./filename.sh is a POSIX-compatible bash?

rupert

unread,
Jan 3, 2009, 5:20:50 PM1/3/09
to
> t=$path_name/bozo/clown

See my post to Bit Twister:

David W. Hodgins

unread,
Jan 3, 2009, 6:08:03 PM1/3/09
to
On Sat, 03 Jan 2009 17:16:39 -0500, rupert <rup...@web-ideas.com.au> wrote:

> Interesting, I'm starting to understand this a little better...
> now the following works fine:
>
> #/bin/bash

Change the above to
#!/bin/bash

Regards, Dave Hodgins

--
Change nomail.afraid.org to ody.ca to reply by email.
(nomail.afraid.org has been set up specifically for
use in usenet. Feel free to use it yourself.)

Bit Twister

unread,
Jan 3, 2009, 6:17:04 PM1/3/09
to

Then change the path_name variable to =/home/clown/ideas/somestuff.

Chris F.A. Johnson

unread,
Jan 3, 2009, 9:03:15 PM1/3/09
to
On 2009-01-03, John Hasler wrote:
> rupert writes:
>> but I want to continue to program in my Borne-again-shell with #!/bin/
>> bash (or #!/bin/sh as I gather ubuntu 8.10 is bash by default).
>
> When Bash is called as "sh" it tries to be POSIX-compatible and so disables
> many extensions.

I don't know of any extensions that are disabled. The main
difference is that it doesn't source the usual file (.bash_profile
or .bashrc); that doesn't normally happen in a script anyway.

> If you want to use Bash features use Bash and call it as
> "bash".


--
Chris F.A. Johnson, author | <http://cfaj.freeshell.org>
Shell Scripting Recipes: | My code in this post, if any,
A Problem-Solution Approach | is released under the
2005, Apress | GNU General Public Licence

Eric Pozharski

unread,
Jan 3, 2009, 2:02:24 PM1/3/09
to
On 2009-01-03, rupert <rup...@web-ideas.com.au> wrote:

apt-get install bash

(supposing your C<bash> is version 2 or older)

--
Torvalds' goal for Linux is very simple: World Domination
Stallman's goal for GNU is even simpler: Freedom

Eric Pozharski

unread,
Jan 3, 2009, 2:04:00 PM1/3/09
to

Looking at B<${parameter/pattern/string}> description in bash(1) I
should say that your code is far from 'like'. IMHO implementing
B<${//}> expansion using only tools in F</bin/*> is fscking challange.
However, in case C<pattern> has none metacharacter, then

t=`echo $path_name | sed 's,bozo,clown,'`

would suffice.

John Hasler

unread,
Jan 3, 2009, 9:41:56 PM1/3/09
to
I wrote:
> When Bash is called as "sh" it tries to be POSIX-compatible and so disables
> many extensions.

Chris F.A. Johnson writes:
> I don't know of any extensions that are disabled.

You're right. I thought it went into POSIX mode but it just attempts to do
a POSIX startup.

Chris F.A. Johnson

unread,
Jan 3, 2009, 10:35:58 PM1/3/09
to
On 2009-01-04, John Hasler wrote:
> I wrote:
>> When Bash is called as "sh" it tries to be POSIX-compatible and so disables
>> many extensions.
>
> Chris F.A. Johnson writes:
>> I don't know of any extensions that are disabled.
>
> You're right. I thought it went into POSIX mode but it just attempts to do
> a POSIX startup.

Even in POSIX mode, most extensions are not disabled.

One of the few things that is different in POSIX mode is a variable
assignment before a special builtin command, e.g.:

$ unset POSIXLY_CORRECT
$ q=uiop
$ q=qwerty set -- whatever
$ echo $q
uiop
$ POSIXLY_CORRECT=1
$ q=qwerty set -- whatever
$ echo $q
qwerty

rupert

unread,
Jan 4, 2009, 12:10:48 AM1/4/09
to
>         apt-get install bash
>
> (supposing your C<bash> is version 2 or older)

rupert@mycomp:~/Desktop$ bash --version
GNU bash, version 3.2.39(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.

This seems resent enough. Unless there's a recent bug...

rupert

unread,
Jan 4, 2009, 12:17:04 AM1/4/09
to
> > #/bin/bash
>
> Change the above to
> #!/bin/bash
>
> Regards, Dave Hodgins
My mistake, that completely explains it. Works fine now. bash
filename.sh implicitly runs bash no matter if I muck up the shebang: ./
filename.sh relies on the shebang to be correct. Thanks Dave.

Martin Vaeth

unread,
Jan 4, 2009, 4:49:22 AM1/4/09
to
Eric Pozharski <why...@pozharski.name> wrote:
>> Unfortunately, there is none. You must program it manually using
>> something like
>> t=${path_name##bozo*}clown${path_name%*bozo}
>
> Looking at B<${parameter/pattern/string}> description in bash(1) I
> should say that your code is far from 'like'.

What is unclear about "program it manually"?

> IMHO implementing
> B<${//}> expansion using only tools in F</bin/*> is fscking challange.

Not really: It is not so hard to code the above as a function,
and doing a loop in this function will also implement ${//}

> However, in case C<pattern> has none metacharacter, then
>
> t=`echo $path_name | sed 's,bozo,clown,'`

A variable quoting is missing. Moreover, to avoid the usual problems
with echo better use printf:
t=`printf '%s' "$path_name" | sed 's,bozo,clown'`

However, this requires much more resources. Moreover, it won't work as
expected if "$path_name" ends with spaces/newlines.

noi ance

unread,
Jan 4, 2009, 4:41:13 PM1/4/09
to
On Sat, 03 Jan 2009 14:20:50 -0800, rupert typed this message:

Then path_name is still correct but you need
: t=$path_name

: $path_name is /home/clown/ideas/somestuff already
: echo $path_name returns /home/clown/ideas/somestuff

: t=$path_name/bozo/clown
: echo $t returns /home/bozo/ideas/somestuff/bozo/clown

t=$(path_name) assumes path_name is an executable
t=${path_name} I have no idea what it does, may assigns string
"{path_name}" to t

Chris F.A. Johnson

unread,
Jan 4, 2009, 6:11:03 PM1/4/09
to
On 2009-01-03, Eric Pozharski wrote:
...

> Looking at B<${parameter/pattern/string}> description in bash(1) I
> should say that your code is far from 'like'. IMHO implementing
> B<${//}> expansion using only tools in F</bin/*> is fscking challange.

Not hard, really:

_sub()
{
_SUB=$1
[ -n "$2" ] || return 1 ## nothing to search for: error
s_srch=${2} ## pattern to replace
rep=$3 ## replacement string
case $_SUB in
*$s_srch*) ## if pattern exists in the string
sr1=${_SUB%%$s_srch*} ## take the string preceding the first match
sr2=${_SUB#*$s_srch} ## and the string following the first match
_SUB=$sr1$rep$sr2 ## and sandwich the replacement string between them
;;
*) return 1 ;; ## if the pattern does not exist, return an error code
esac
}

sub()
{
_sub "$@"
printf "%s\n" "$_SUB"
}

_gsub()
{
## clear variable in case of failure
_GSUB=

## assign the string to sr2
sr2=$1

## return an error if there is no pattern specified
[ -z "$2" ] && return 1

## assign the search pattern to s_srch
s_srch=${2}

## assign the replacement text, if any, to rep
rep=$3

## sr1 will hold the portion of the string that has been processed
sr1=

## loop until sr2 no longer contains the search pattern
while :
do
case $sr2 in
*$s_srch*)

## add the string up to the match,
## and the replacement text, to sr1
sr1=$sr1${sr2%%$s_srch*}$rep

## remove up to the match from sr2
sr2=${sr2#*$s_srch}
;;
*) break ;;
esac
done
_GSUB=$sr1$sr2
}

gsub()
{
_gsub "$@" &&
printf "%s\n" "$_GSUB"

Martin Vaeth

unread,
Jan 5, 2009, 4:32:27 AM1/5/09
to
Chris F.A. Johnson <cfajo...@gmail.com> wrote:
> On 2009-01-03, Eric Pozharski wrote:
> ...
>> Looking at B<${parameter/pattern/string}> description in bash(1) I
>> should say that your code is far from 'like'. IMHO implementing
>> B<${//}> expansion using only tools in F</bin/*> is fscking challange.
>
> Not hard, really:

I haven't checked, but probably the unquoted $s_srch here can cause
trouble if s_srch contains special symbols:

> *$s_srch*)
> sr1=${_SUB%%$s_srch*}
> sr2=${_SUB#*$s_srch}

Morever, apparently you mean to call the function
with `sub ...` or `gsub ...` or
with $(sub ..) or $(gsub ..), respectively.
But this has the same problem as `sed -e s/...` or $(sed -e s/...):
It omits trailing spaces/newlines of the result.
Therefore, IMHO the only clean way of such a function is by passing
the variable name as a first argument. Actually, the resulting code is
not so long although rather clumsy.
You can find it in the "Replace" function in functions-eix.sh[.in]
of the eix project, see https://svn.gentooexperimental.org/eix/trunk/src
The code can even be shortened somewhat if the number of replacements
should not be counted.

Jasen Betts

unread,
Jan 5, 2009, 5:29:25 AM1/5/09
to
On 2009-01-03, rupert <rup...@web-ideas.com.au> wrote:
>
> the following does not work:
> username$ chmod 744 filename.sh
> username$ ./filename.sh
>
> malloc: ../bash/dispose_cmd.c:241: assertion botched
> free: called with unallocated block argument
> Aborting...Aborted

Your bash is broken, try a newer version, if you can't find one that
works report this as a bug (with instructions how to replicate it) and
try an older bash.

Eric Pozharski

unread,
Jan 5, 2009, 3:47:48 AM1/5/09
to
On 2009-01-04, Martin Vaeth <va...@mathematik.uni-wuerzburg.de> wrote:
> Eric Pozharski <why...@pozharski.name> wrote:
*SKIP*

>> IMHO implementing
>> B<${//}> expansion using only tools in F</bin/*> is fscking challange.
>
> Not really: It is not so hard to code the above as a function,
> and doing a loop in this function will also implement ${//}

I didn't say it's hard, I've said it's fscking challenge.

>> However, in case C<pattern> has none metacharacter, then
>>
>> t=`echo $path_name | sed 's,bozo,clown,'`
>
> A variable quoting is missing. Moreover, to avoid the usual problems
> with echo better use printf:
> t=`printf '%s' "$path_name" | sed 's,bozo,clown'`
>
> However, this requires much more resources. Moreover, it won't work as
> expected if "$path_name" ends with spaces/newlines.

Let's stop at this point. I think, that David W. Hodgins already solved
OP's problem anyway.

undisclosed

unread,
Sep 10, 2009, 8:12:34 AM9/10/09
to

Hi ,

you can continue to work in Bash script by adding the following
changes in passwd file present at the path cd /etc/

in passwd file under root change the
root:x:0:0:Super-User:/root:/bin/ksh

to root:x:0:0:Super-User:/root:/bin/bash

rupert;1253510 Wrote:
> I've been going through a very good bash scripting tutorial here:

> 'Parameter Substitution'
> (http://tldp.org/LDP/abs/html/parameter-substitution.html#PSUB2)


>
> It is based on the Korne-shell (so naturally the she-bang is: #!/bin/
> ksh)
> but I want to continue to program in my Borne-again-shell with #!/bin/
> bash
> (or #!/bin/sh as I gather ubuntu 8.10 is bash by default).
>
> #!/bin/bash
> #this causes a Bad substitution error...
> path_name=/home/bozo/ideas/somestuff
> t=${path_name/bozo/clown} #this will fail here...
> echo $t
> exit 0
>
> what is the Bash alternative to do a substitution like this?


--
venkatareddy

Eric

unread,
Sep 10, 2009, 9:45:55 PM9/10/09
to
from the Advanced Bash Scripting pdf:
Substring Replacement
${string/substring/replacement}
Replace first match of $substring with $replacement.
${string//substring/replacement}
Replace all matches of $substring with $replacement.

stringZ=abcABC123ABCabc
echo ${stringZ/abc/xyz} # xyzABC123ABCabc
# Replaces first match of 'abc' with 'xyz'.

echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
# Replaces all matches of 'abc' with # 'xyz'.

Your script should work.
Eric

0 new messages