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?
> path_name=/home/bozo/ideas/somestuff
> t=${path_name/bozo/clown} #this will fail here...
t=${path_name}/bozo/clown
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}
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$
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
t=$path_name/bozo/clown
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
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?
See my post to Bit Twister:
> 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.)
Then change the path_name variable to =/home/clown/ideas/somestuff.
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
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
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.
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@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...
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.
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
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"
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.
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.
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.
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
Your script should work.
Eric