COMPGROUPS.NET | Browse | Post | Groups | Users | Stream | About | |

### parameter expansion

• Email
• Follow

#!/bin/bash

tr -s' ' | cut -d' ' -f${*/%/,} Example: ls -l | ./script 1 5 I would print the first and the 5th field of the input stream. cut -d' ' -f1 -f5 -> cut -d' '${*/#/-f} don't run
cut -d' ' -f1, 5,     -> cut -d' ' ${*/%/,} don't run I would expand -f1,5,7 etc. How can I use parameters expansion in this script? davide [I'm sorry for my English...]   0 Reply davide 2/6/2004 11:24:40 AM See related articles to this posting On Fri, 06 Feb 2004 at 11:24 GMT, davide moro wrote: > #!/bin/bash > > tr -s' ' | cut -d' ' -f${*/%/,}
>
> Example: ls -l | ./script 1 5
> I would print the first and the 5th field of the input stream.
>
> cut -d' ' -f1 -f5    -> cut -d' ' ${*/#/-f} don't run > cut -d' ' -f1, 5, -> cut -d' '${*/%/,} don't run
>
> I would expand -f1,5,7 etc.
> How can I use parameters expansion in this script?

#v+
#!/bin/bash

var="$@" tr -s ' ' | cut -d ' ' -f "${var// /,}"
#v-

--
Chris F.A. Johnson                        http://cfaj.freeshell.org
===================================================================
My code (if any) in this post is copyright 2004, Chris F.A. Johnson
and may be copied under the terms of the GNU General Public License

 0

2004-02-06, 11:24(+00), davide moro:
> #!/bin/bash
>
> tr -s' ' | cut -d' ' -f${*/%/,} > > Example: ls -l | ./script 1 5 > I would print the first and the 5th field of the input stream. > > cut -d' ' -f1 -f5 -> cut -d' '${*/#/-f} don't run
> cut -d' ' -f1, 5,     -> cut -d' ' ${*/%/,} don't run > > I would expand -f1,5,7 etc. > How can I use parameters expansion in this script? #! /bin/sh - IFS=, tr -s ' ' | cut -d' ' -f"$*"

(not with Bourne shell nor ash, but with every POSIX compliant
shell [including bash] and zsh)

With zsh: ${(j",")@} -- St�phane ["Stephane.Chazelas" at "free.fr"]   0 Reply Stephane 2/6/2004 2:41:45 PM Very kindly from you, I really appreciate your help. Thanks! Regards, davide   0 Reply davide 2/6/2004 2:58:36 PM 2004-02-6, 13:50(+00), Chris F.A. Johnson: [...] > #!/bin/bash > > var="$@"
> tr -s ' ' | cut -d ' ' -f "${var// /,}" [...] Note, to follow-up on my post on the other thread, that the fact that in var="$@", the positional parameters are joined with
spaces is undocumented (in zsh, they are joined with the first
character of IFS, and it's documented)

Worse:
bash-2.05b$set a b c; IFS=,; a=$*; b="$*" bash-2.05b$ echo "$a" a,b,c bash-2.05b$ echo "$b" a,b,c bash-2.05b$ IFS=; a=$*; b="$*"
bash-2.05b$echo "$a"
a b c
bash-2.05b$echo "$b"
abc

So, in assignment, in bash, the only thing you can rely on in an
assignment WRT to $* and$@ is:

var="$*" The other ones are not documented and may have erratic effects that could change from a version of bash to another as it's not documented (ksh93 behavior is different, and POSIX is not clear on that point too, and if it makes things clearer, chances are that the specification will get adapted so that ksh93 is conformant): var=$*
var=$@ var="$@"

Well, you can assume that as long as you don't change IFS, they
will always result in the positional parameters joined with
space.

--
St�phane                      ["Stephane.Chazelas" at "free.fr"]

 0

On Fri, 6 Feb 2004 16:43:26 +0100, Stephane CHAZELAS

>2004-02-6, 13:50(+00), Chris F.A. Johnson:
>[...]
>> #!/bin/bash
>>
>> var="$@" >> tr -s ' ' | cut -d ' ' -f "${var// /,}"
>[...]
>
>Note, to follow-up on my post on the other thread, that the fact
>that in var="$@", the positional parameters are joined with >spaces is undocumented (in zsh, they are joined with the first >character of IFS, and it's documented) > No, you're failing again due to ignorance of bash info pages. Under special parameters heading: <quote> @' Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$@"' is equivalent to "$1" "$2" ...'.
When there are no positional parameters, "$@"' and $@' expand to
nothing (i.e., they are removed).

</quote>

>Worse:
>bash-2.05b$set a b c; IFS=,; a=$*; b="$*" >bash-2.05b$ echo "$a" >a,b,c >bash-2.05b$ echo "$b" >a,b,c >bash-2.05b$ IFS=; a=$*; b="$*"
>bash-2.05b$echo "$a"
>a b c
>bash-2.05b$echo "$b"
>abc
>

You assign null to IFS, and the behaviour conforms, well you guessed, to
related info page anyway:

<quote>
*'
Expands to the positional parameters, starting from one.  When the
expansion occurs within double quotes, it expands to a single word
with the value of each parameter separated by the first character
of the IFS' special variable.  That is, "$*"' is equivalent to "$1C$2C..."', where C is the first character of the value of the IFS' variable. If IFS' is unset, the parameters are separated by spaces. If IFS' is null, the parameters are joined without intervening separators. </quote> I'm getting tired and bored of cut'n paste, are you not? >So, in assignment, in bash, the only thing you can rely on in an >assignment WRT to$* and $@ is: > >var="$*"
>
>The other ones are not documented and may have erratic effects
>that could change from a version of bash to another as it's not
>documented (ksh93 behavior is different, and POSIX is not
>clear on that point too, and if it makes things clearer, chances
>are that the specification will get adapted so that ksh93 is
>conformant):
>
>var=$* >var=$@
>var="$@" > >Well, you can assume that as long as you don't change IFS, they >will always result in the positional parameters joined with >space.   0 Reply A 2/6/2004 8:10:56 PM 2004-02-06, 22:10(+02), A Alper ATICI: [...] >>Note, to follow-up on my post on the other thread, that the fact >>that in var="$@", the positional parameters are joined with
>>spaces is undocumented (in zsh, they are joined with the first
>>character of IFS, and it's documented)
>>
> No, you're failing again due to ignorance of bash info pages.
>
>
> <quote>
> @'
>      Expands to the positional parameters, starting from one.  When the
>      expansion occurs within double quotes, each parameter expands to a
>      separate word.  That is, "$@"' is equivalent to "$1" "$2" ...'. > When there are no positional parameters, "$@"' and $@' expand to > nothing (i.e., they are removed). [...] I can see no mention of "space" in the above. I can see that "$@" expands to the list of positional parameters, but in the
context of an assignment to a string type variable, it makes no
sense (same in case statement, or [[ ]], of ${..#$@} and in many
other places). So, it has to be documented, and it's not, even
in the info page. That's simple enough, it's just a matter of �
in contexts where $@ can't expand to a list, then both$@ and
"$@" expand to the concatenation of positional arguments with spaces inbetween, and$* expands to the concatenation of
positional parameters with the first char of IFS (or " " if IFS
is empty or unset) inbetween �.

>>bash-2.05b$set a b c; IFS=,; a=$*; b="$*" >>bash-2.05b$ echo "$a" >>a,b,c >>bash-2.05b$ echo "$b" >>a,b,c >>bash-2.05b$ IFS=; a=$*; b="$*"
>>bash-2.05b$echo "$a"
>>a b c
>>bash-2.05b$echo "$b"
>>abc
>>
>
> You assign null to IFS, and the behaviour conforms, well you guessed, to
> related info page anyway:
>
> <quote>
> *'
>      Expands to the positional parameters, starting from one.  When the
>      expansion occurs within double quotes, it expands to a single word
>      with the value of each parameter separated by the first character
>      of the IFS' special variable.  That is, "$*"' is equivalent to > "$1C$2C..."', where C is the first character of the value of the > IFS' variable. If IFS' is unset, the parameters are separated > by spaces. If IFS' is null, the parameters are joined without > intervening separators. Yes, and? I was speaking of$*, $@, "$@" not documented in assignment in
that case. The part you quote speaks of "$*" for which I also said that it was documented. > </quote> > > I'm getting tired and bored of cut'n paste, are you not? Could you please cut&paste a last one for me: the one that explains why in set a b c;IFS=",", a=$*, $a is "a,b,c" while in set a b c;IFS="", a=$*, $a is "a b c" (note that there are also serious bugs in UTF-8 locales with non-ascii characters, but I guess UTF-8 support is still in a very early alpha stage). -- St�phane ["Stephane.Chazelas" at "free.fr"]   0 Reply Stephane 2/6/2004 8:38:25 PM On Fri, 6 Feb 2004 21:38:25 +0100, Stephane CHAZELAS <this.address@is.invalid> wrote: >> >> Under special parameters heading: >> >> <quote> >> @' >> Expands to the positional parameters, starting from one. When the >> expansion occurs within double quotes, each parameter expands to a >> separate word. That is, "$@"' is equivalent to "$1" "$2" ...'.
>>      When there are no positional parameters, "$@"' and $@' expand to
>>      nothing (i.e., they are removed).
>[...]
>
>I can see no mention of "space" in the above. I can see that
>"$@" expands to the list of positional parameters, but in the >context of an assignment to a string type variable, it makes no >sense (same in case statement, or [[ ]], of${..#$@} and in many >other places). So, it has to be documented, and it's not, even [...] You seem to have a problem wrt "Expands to the positional parameters, starting from one" statement, you may be right, and I'd say "have a look at arrays":$ ary[0]=aa ary[1]=bb c=${ary[*]} d=${ary[@]}; echo $c; echo$d
aa bb
aa bb

If you agree an unseparated list is not an option in this case, then it
boils down to "why is it a space separated list?", but I regret I don't
have time to join that discussion.

Although I have not examined bash source code, it is obvious $* and$@ are
implemented as arrays, therefore their behaviour is not unreliable,
undocumented, erratic, etc to me. OTOH, I guess you've spotted a bash bug,
which is better obverved below:

$set a b c; IFS=, a=$* b="$*"; echo$a; echo "$a"; echo$b; echo "$b" a b c a,b,c a b c a,b,c$ unset IFS
$set a b c; a=$* b="$*"; echo$a; echo "$a"; echo$b; echo "$b" a b c a b c a b c a b c "$a" and "$b" exhibit "$*" specific behaviour as documented.
$a and$b expand to positional parameters starting from one, as in arrays.
So far so good.

$set a b c; IFS= a=$* b="$*"; echo$a; echo "$a"; echo$b; echo "$b" a b c a b c abc abc Now, I'd expect 2nd and 3rd lines exchanged in the output above. Unless there's a special case when IFS is null, this could be a bug, or I'm terribly wrong somewhere... regards,   0 Reply A 2/7/2004 2:24:39 PM On Sat, 07 Feb 2004 at 14:24 GMT, A Alper ATICI wrote: > >$ set a b c; IFS= a=$* b="$*"; echo $a; echo "$a"; echo $b; echo "$b"
> a b c
> a b c
> abc
> abc
>
> Now, I'd expect 2nd and 3rd lines exchanged in the output above.
> Unless there's a special case when IFS is null, this could be a bug,
> or I'm terribly wrong somewhere...

When $* is quoted, it's a single word; when it's not, each argument is a separate word, and$IFS is not used.

You have assigned a single word, "abc" (the three arguments
separated by the first character of $IFS, which is empty), to$b,
but 3 words to $a. There's nothing wrong with the output; you might question why the three arguments were separated by spaces when assigned to$a. AFAICS, the separator is undefined. Once that's done, however,
the output is entirely correct.

The assignment to $b is well-defined, and once assigned,$b
contains only a single word. There is no conceivable way that
echoing "$b" or$b can produce anything but abc.

--
Chris F.A. Johnson                        http://cfaj.freeshell.org
===================================================================
My code (if any) in this post is copyright 2004, Chris F.A. Johnson
and may be copied under the terms of the GNU General Public License

 0

On 8 Feb 2004 17:56:48 GMT, "Chris F.A. Johnson" <c.fa.johnson@rogers.com>
wrote:

>On Sat, 07 Feb 2004 at 14:24 GMT, A Alper ATICI wrote:
>>
>> $set a b c; IFS= a=$* b="$*"; echo$a; echo "$a"; echo$b; echo "$b" >> a b c >> a b c >> abc >> abc >> >> Now, I'd expect 2nd and 3rd lines exchanged in the output above. >> Unless there's a special case when IFS is null, this could be a bug, >> or I'm terribly wrong somewhere... > > When$* is quoted, it's a single word; when it's not, each argument
>   is a separate word, and $IFS is not used. > This explanation conflicts with the case when IFS=,$ set a b c; IFS=, a=$* b="$*"; echo $a; echo "$a"; echo $b; echo "$b"
a b c
a,b,c
a b c
a,b,c

$* is not quoted when assigned to a, however IFS is used in echo "$a"


 0

2004-02-8, 17:56(+00), Chris F.A. Johnson:
[...]
>    When $* is quoted, it's a single word; when it's not, each argument > is a separate word, and$IFS is not used.
[...]

Only in list contexts, but in scalar assignments and various
other place, you can't have "separate words" as it's a string
context.

And then, it is undocumented, that was my point.

Note that in

printf '<%s>\n' $* in Bourne shells, the fact that printf gets passed the list of arguments is because$* is splitted according to IFS as any
other variable. $* is not a special variable in Bourne shell (except that its value is dynamically built as the concatenation of the positional parameters with spaces inbetween) In Bourne shells: set "a:b" "A B" IFS=: printf '<%s>\n'$*

gives:

<a>
<b A B>

(because $* is joined with spaces, and thus not splitted there) In Bourne shell,$@ is exactly the same as $* except when inside double quotes in list context in which case it is expanded to the list of positional parameters:$ printf '<%s>\n' $@ <a> <b A B>$ printf '<%s>\n' "$@" <a:b> <A B> That's very simple and consistent. The zsh way is very similar (when word splitting is activated). In bash, you don't really know how it works. In cmd$*, it seems
that you always get the list of parameters (word splitted). If
you disable word splitting (IFS=), the arguments are preserved,
even the empty ones:

$set "a b" "" "c d"$ IFS=
$printf '<%s>\n'$*
<a b>
<>
<c d>

That would indicate that the separation is not due to word
splitting. However, in

LANG=fr_FR.UTF-8 bash -c "
set a b
IFS=\$'\303\251' # � in UTF8 printf %s, \$* | od -tc"
0000000   a 303   b   ,
0000003

There's a general confusion, in bash multibyte support between
"character" and "byte". Here it seems that the value of $* is built as the positional parameters joined with the first *byte* of IFS, and so is not word splitted because the result is a string that doesn't contain the '�' *character*. So, it seems that at least in some cases, you have a behavior similar as the Bourne shell one. > You have assigned a single word, "abc" (the three arguments > separated by the first character of$IFS, which is empty), to $b, > but 3 words to$a.

You can't assign 3 words to a string-type variable, that makes
no sense. What you can do is assigning the concatenation of 3
words with whatever character inbetween.

--
St�phane                      ["Stephane.Chazelas" at "free.fr"]

 0

On Sun, 08 Feb 2004 at 19:02 GMT, A Alper ATICI wrote:
> On 8 Feb 2004 17:56:48 GMT, "Chris F.A. Johnson" <c.fa.johnson@rogers.com>
> wrote:
>
>>On Sat, 07 Feb 2004 at 14:24 GMT, A Alper ATICI wrote:
>>>
>>> $set a b c; IFS= a=$* b="$*"; echo$a; echo "$a"; echo$b; echo "$b" >>> a b c >>> a b c >>> abc >>> abc >>> >>> Now, I'd expect 2nd and 3rd lines exchanged in the output above. >>> Unless there's a special case when IFS is null, this could be a bug, >>> or I'm terribly wrong somewhere... >> >> When$* is quoted, it's a single word; when it's not, each argument
>>   is a separate word, and $IFS is not used. >> > > This explanation conflicts with the case when IFS=, > >$ set a b c; IFS=, a=$* b="$*"; echo $a; echo "$a"; echo $b; echo "$b"
> a b c
> a,b,c
> a b c
> a,b,c
>
> $* is not quoted when assigned to a, however IFS is used in echo "$a"

No, IFS is used in the assignment to $a. As I said, when$* is not
quoted, the separator is undefined. Apparently, it uses a space
when IFS="", otherwise it uses the first character of $IFS. The output is exactly as it should be, given the values assigned to$a and $b. man bash: echo [-neE] [arg ...] Output the args, separated by spaces, followed by a newline. When IFS=",",$a and $b are both read as three arguments (they both contain "a,b,c"), "$a" and "$b" are read as one argument.$ set a b c; IFS=, a=$* b="$*"; IFS=; echo $a; echo "$a"; echo $b; echo "$b"
a,b,c
a,b,c
a,b,c
a,b,c

--
Chris F.A. Johnson                        http://cfaj.freeshell.org
===================================================================
My code (if any) in this post is copyright 2004, Chris F.A. Johnson
and may be copied under the terms of the GNU General Public License

 0

On 8 Feb 2004 19:57:33 GMT, "Chris F.A. Johnson" <c.fa.johnson@rogers.com>
wrote:

[...]
>
>       echo [-neE] [arg ...]
>              Output the args, separated by spaces, followed by a
>              newline.
>
>
>   When IFS=",", $a and$b are both read as three arguments (they both
>   contain "a,b,c"), "$a" and "$b" are read as one argument.
>

bash :? parameter expansion
From the man-pages: ${parameter:?word} Display Error if Null or Unset. If parameter is null or unset, the expansion of word (or a message to that effect if word is not present) is written to the standard error and the shell, if it is not interactive, exits. Otherwise, the value of parameter is sub- stituted. This works as documented. However, I found out (with bash 3.0), that omitting the colon also works, i.e. echo${XX?not set} aborts with "XX: not set" if XX is null or unset, and echos the content of XX otherwise. ...

bash parameter expansion
Given is the following path: $echo$PWD /tmp/a/b/c To find the basename I can use: $echo${PWD##*/} c But how can I extract the second but last part (b)? Is this possible with just parameter expansion? On 19.02.2014 11:03, Andreas Kernis wrote: > Given is the following path: > > $echo$PWD > /tmp/a/b/c > > To find the basename I can use: > > $echo${PWD##*/} > c > > But how can I extract the second but last part (b)? There are several possibilities; a simple one is... x=${PWD%/*} ; echo${x##*/} Other options... ...

Substituting parameter expansions and POSIX
In ksh93, to make a substitution in a parameter expansion you say ${parameter/pattern/string} or${parameter//pattern/string}. To anchor the pattern, ${parameter/#pattern/string} or${parameter/%pattern/string} is used. Bash on the other hand only allows the first two alternatives, but to anchor the pattern you can add a '#' or '%', i.e. as in the second two alternatives above or ${parameter//#pattern/string}. This is causing me problems porting a script from ksh to bash, which contains${parameter//%1/string}. The desire here is to replace every occurence of '%1' with...

POSIX Shell and Parameter Expansion
I'm interested in construction like ${x:-} Is it a correct shell token? Judging from this document http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html section 2.6.2 this is not correct since the word after ":-" is not optional. (Compare with ":?" where the word is optional.) But shell implementations available to me (bash,dash,zsh) all accept it. Do they get it wrong? Roman Cheplyaka wrote: > I'm interested in construction like >${x:-} > Is it a correct shell token? Yes, I'd say; a word can be empty, as it is maybe more appar...

#include parameter from a macro expansion
In a C file I want to include a file depending on the macro NAME. For example, if it is "foo", the file to include will be "foo \foo_params.h". If it is bar, the include file will be "bar \bar_params.h". I tried to achieve this, but without success. I started from: #define INCLUDE_FILE "foo\foo_params.h" #include INCLUDE_FILE and it worked. After that I tried the following: #define INCLUDE_FILE "foo\foo" ## "_params.h" #include INCLUDE_FILE without success... pozz <pozzugno@gmail.com> writes: > In a C file I want to in...