Discussion:
Recommended way to truncate a shell variable value in autoconf
Dale Visser
2014-02-21 22:08:02 UTC
Permalink
I have a macro argument that I would like to place in a shell variable, but with a catch. I want to truncate it at the first space or comma. I have code that works for me (in Ubuntu), like this:

my_var="$1"
my_var=${my_var%%\ *}
my_var=${my_var%%,*}

However, I read at https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Shell-Substitutions.html#Shell-Substitutions that this construct "[does] not work with many traditional shells, e.g., Solaris 10 /bin/sh."

I am at a loss to figure out an acceptable "autoconf portable way" to accomplish this. I suspect some usage of m4_split (https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Text-processing-Macros.html#index-m4_005fsplit-1486) could be the answer, but haven't been able to figure out how to make it work correctly.

Help?
Eric Blake
2014-02-21 22:26:10 UTC
Permalink
On 02/21/2014 03:23 PM, Eric Blake wrote:
> On 02/21/2014 03:08 PM, Dale Visser wrote:
>> I have a macro argument that I would like to place in a shell variable, but with a catch. I want to truncate it at the first space or comma. I have code that works for me (in Ubuntu), like this:
>>
>> my_var="$1"
>> my_var=${my_var%%\ *}
>> my_var=${my_var%%,*}
>>

> If you guarantee that your shell is capable (right now, that could be
> done by using the undocumented _AS_DETECT_REQUIRED macro), then your way
> is portable. Until then, the only portable fallback to this particular
> problem is the use of 'expr' pattern matching and/or sed scripts. :(

Or mess with IFS splitting:

my_var=$1
IFS=' ,'
set dummy $my_var
shift
IFS=' '' ''
'
my_var=$1

--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
Eric Blake
2014-02-21 22:27:04 UTC
Permalink
On 02/21/2014 03:26 PM, Eric Blake wrote:
> On 02/21/2014 03:23 PM, Eric Blake wrote:
>> On 02/21/2014 03:08 PM, Dale Visser wrote:
>>> I have a macro argument that I would like to place in a shell variable, but with a catch. I want to truncate it at the first space or comma. I have code that works for me (in Ubuntu), like this:
>>>
>>> my_var="$1"
>>> my_var=${my_var%%\ *}
>>> my_var=${my_var%%,*}
>>>
>
>> If you guarantee that your shell is capable (right now, that could be
>> done by using the undocumented _AS_DETECT_REQUIRED macro), then your way
>> is portable. Until then, the only portable fallback to this particular
>> problem is the use of 'expr' pattern matching and/or sed scripts. :(
>
> Or mess with IFS splitting:
>
> my_var=$1
> IFS=' ,'
> set dummy $my_var
> shift
> IFS=' '' ''
> '
> my_var=$1

Oh, and be sure to use 'set -f' for the duration of your IFS splitting,
to avoid globbing.

--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
Eric Blake
2014-02-21 22:23:31 UTC
Permalink
On 02/21/2014 03:08 PM, Dale Visser wrote:
> I have a macro argument that I would like to place in a shell variable, but with a catch. I want to truncate it at the first space or comma. I have code that works for me (in Ubuntu), like this:
>
> my_var="$1"
> my_var=${my_var%%\ *}
> my_var=${my_var%%,*}
>
> However, I read at https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Shell-Substitutions.html#Shell-Substitutions that this construct "[does] not work with many traditional shells, e.g., Solaris 10 /bin/sh."

What we NEED to do is finally bite the bullet to require XSI parameter
expansion of any shell that runs configure (we've already had snoop code
in the wild to prove that such a shell can be found, and no one has
submitted bug reports from any museum machine where the snoop has
triggered - even Solaris, with its ancient /bin/sh, has a better shell
that is always installed and easy enough to find). Then we could
simplify quite a bit of configure by actually using these substitutions.

>
> I am at a loss to figure out an acceptable "autoconf portable way" to accomplish this. I suspect some usage of m4_split (https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Text-processing-Macros.html#index-m4_005fsplit-1486) could be the answer, but haven't been able to figure out how to make it work correctly.

If you guarantee that your shell is capable (right now, that could be
done by using the undocumented _AS_DETECT_REQUIRED macro), then your way
is portable. Until then, the only portable fallback to this particular
problem is the use of 'expr' pattern matching and/or sed scripts. :(

--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
Dale Visser
2014-02-21 23:50:36 UTC
Permalink
> Date: Fri, 21 Feb 2014 15:23:31 -0700
> From: ***@redhat.com
> To: ***@live.com; ***@gnu.org
> Subject: Re: Recommended way to truncate a shell variable value in autoconf
>
> ...
> is portable. Until then, the only portable fallback to this particular
> problem is the use of 'expr' pattern matching and/or sed scripts. :(

I've figured a working alternative using successive calls to `expr STRING : REGEXP`

But then again I notice in the autoconf docs (https://www.gnu.org/software/autoconf/manual/autoconf.html#Limitations-of-Usual-Tools) this:

"Don't use length, substr, match and index."

Since "STRING : REGEXP" does the same thing as "match STRING REGEXP", does that mean I'm out of luck with this approach, too?
Eric Blake
2014-02-21 23:57:28 UTC
Permalink
On 02/21/2014 04:50 PM, Dale Visser wrote:
>> Date: Fri, 21 Feb 2014 15:23:31 -0700
>> From: ***@redhat.com
>> To: ***@live.com; ***@gnu.org
>> Subject: Re: Recommended way to truncate a shell variable value in autoconf
>>
>> ...
>> is portable. Until then, the only portable fallback to this particular
>> problem is the use of 'expr' pattern matching and/or sed scripts. :(
>
> I've figured a working alternative using successive calls to `expr STRING : REGEXP`
>
> But then again I notice in the autoconf docs (https://www.gnu.org/software/autoconf/manual/autoconf.html#Limitations-of-Usual-Tools) this:
>
> "Don't use length, substr, match and index."
>
> Since "STRING : REGEXP" does the same thing as "match STRING REGEXP", does that mean I'm out of luck with this approach, too?

'string : regexp' is portable. 'match string regexp' is not. For
example this use of expr is already present in pretty much any configure
file generated by modern autoconf:

as_echo_body='eval expr "X$1" : "X\\(.*\\)"'

But if you're trying to modify autoconf proper, I really do think it's
time that we start requiring a shell that supports XSI variable
expansion, rather than forking expr right and left.

--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
Dale Visser
2014-02-22 00:05:03 UTC
Permalink
> Date: Fri, 21 Feb 2014 16:57:28 -0700
> From: ***@redhat.com
> To: ***@live.com; ***@gnu.org
> Subject: Re: Recommended way to truncate a shell variable value in autoconf
>
> 'string : regexp' is portable. 'match string regexp' is not. For
> example this use of expr is already present in pretty much any configure
> file generated by modern autoconf:
>
> as_echo_body='eval expr "X$1" : "X\\(.*\\)"'

Good. I think I have settled on this, but will go back to the expr solution if you think that would be better:

X=`echo "$X" | sed 's/ .*// ' | sed 's/,.*//'`

By the way, thank you for all your help. :-)
Eric Blake
2014-02-22 00:09:28 UTC
Permalink
On 02/21/2014 05:05 PM, Dale Visser wrote:
>> Date: Fri, 21 Feb 2014 16:57:28 -0700
>> From: ***@redhat.com
>> To: ***@live.com; ***@gnu.org
>> Subject: Re: Recommended way to truncate a shell variable value in autoconf
>>
>> 'string : regexp' is portable. 'match string regexp' is not. For
>> example this use of expr is already present in pretty much any configure
>> file generated by modern autoconf:
>>
>> as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
>
> Good. I think I have settled on this, but will go back to the expr solution if you think that would be better:
>
> X=`echo "$X" | sed 's/ .*// ' | sed 's/,.*//'`

sed|sed is a waste of a fork. Just go with:

X=`echo "$X" | sed 's/[, ].*//'`

--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
Dale Visser
2014-02-22 00:22:03 UTC
Permalink
Eric:

My experience with expr just prior was that it was matching too greedily on the character class. I had just assumed I would need two steps with sed, too. However, I checked and your suggestion works as I need it to.

I think the difference is that in expr, one specifies what part of the expression match to keep. The sed command is specifying what to replace, so in that case greedy matching worked in my favor.

Thank you!
Dale

--
Date: Fri, 21 Feb 2014 17:09:28 -0700
From: ***@redhat.com
To: ***@live.com; ***@gnu.org
Subject: Re: Recommended way to truncate a shell variable value in autoconf


> X=`echo "$X" | sed 's/ .*// ' | sed 's/,.*//'`

sed|sed is a waste of a fork. Just go with:

X=`echo "$X" | sed 's/[, ].*//'`
David A. Wheeler
2014-02-22 02:54:52 UTC
Permalink
Eric Blake said:
> .... Just go with:
> X=`echo "$X" | sed 's/[, ].*//'`

The "sed" is nice and clear.

However, that "echo" will probably cause trouble if $X starts with "-" or has other characters in it.
I presume in this case that $X will *usually* start with "-", so you REALLY don't want to use echo directly.
Unless $X can *only* contain alphanumerics, I suggest replacing echo "$X" with:
printf '%s\n' "$X"
An alternative would be to use AS_ECHO.

Dale Visser, you might want to look here:
https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Portable-Shell.html
and especially:
https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Limitations-of-Builtins.html

--- David A. Wheeler
Dale Visser
2014-02-22 03:37:57 UTC
Permalink
David:

I looked at the docs and see what you mean. Amazing how portability concerns affect even the lowly echo command. I will try replacing

echo "$X"

with

AS_ECHO([$X]).

Thank you!
Dale

Sent from my Windows Phone
________________________________
From: David A. Wheeler<mailto:***@dwheeler.com>
Sent: ‎2/‎21/‎2014 9:55 PM
To: autoconf<mailto:***@gnu.org>
Subject: RE: Recommended way to truncate a shell variable value in autoconf

Eric Blake said:
> .... Just go with:
> X=`echo "$X" | sed 's/[, ].*//'`

The "sed" is nice and clear.

However, that "echo" will probably cause trouble if $X starts with "-" or has other characters in it.
I presume in this case that $X will *usually* start with "-", so you REALLY don't want to use echo directly.
Unless $X can *only* contain alphanumerics, I suggest replacing echo "$X" with:
printf '%s\n' "$X"
An alternative would be to use AS_ECHO.

Dale Visser, you might want to look here:
https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Portable-Shell.html
and especially:
https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Limitations-of-Builtins.html

--- David A. Wheeler

_______________________________________________
Autoconf mailing list
***@gnu.org
https://lists.gnu.org/mailman/listinfo/autoconf
Loading...