Can you give examples?
> An example of this is a case statement
> or an if statement where an integer is
> being compared.
That seems to work for me, both, with quotes or without.
> Doesn't quoting an integer
> make it a string and thus break the compare?
Have you observed such behaviour? Can you give an example?
> What would be the need of quoting an
> integer variable anyway?
None, I suppose.
> Integers can't
> have a space in the middle to complicate
> matters. I'm not trying to asserting anything
> here but am I right about this topic?
I suppose so.
The concern of quoting variables is primarily (but not only) in
context of filenames with spaces; this is espacially important
if you happen to have to process typical WinDOS filenames or if
you stumble across files of someone who stretches the possible
Unix filenames to absurdity.
But using integers the ancient way is nothing I'd nowadays do
anyway, if I don't have to do so (maybe because someone holds a
gun at your head). Once you're used to $((...)) and ((...)) and
using integer variables even without the $ symbol you don't care
any more about the quote question, in the first place. If you
prefer to program "portably", maybe comparing integers with -lt,
-gt, -eq, -ne, etc. enclosed in [...] test programs (or builtins),
occasionally quoting (unnecessarily, yes) integer variables, shall
answer someone who is more conservative than I am. ;-)
Janis
I recall instances in the past where a quoted variable would cause
an error in an integer test if it had leading spaces. I can't find
any current shell that does that.
>> What would be the need of quoting an
>> integer variable anyway?
>
> None, I suppose.
>
>> Integers can't
>> have a space in the middle to complicate
>> matters. I'm not trying to asserting anything
>> here but am I right about this topic?
>
> I suppose so.
If you can be certain that the variable contains a valid integer,
and are sure that $IFS does not contain an integer, then there is
no need to quote it.
> The concern of quoting variables is primarily (but not only) in
> context of filenames with spaces; this is espacially important
> if you happen to have to process typical WinDOS filenames or if
> you stumble across files of someone who stretches the possible
> Unix filenames to absurdity.
It is not only filenames; it is anywhere that the contents of the
variable is not guaranteed to be free of spaces.
> But using integers the ancient way is nothing I'd nowadays do
> anyway, if I don't have to do so (maybe because someone holds a
> gun at your head). Once you're used to $((...)) and ((...)) and
I never use (( ... )); it is not POSIX compliant, and there is no
advantage to it.
> using integer variables even without the $ symbol you don't care
I use $ in arithmetic expressions because there are shells
that fail if it is not there.
> any more about the quote question, in the first place. If you
> prefer to program "portably", maybe comparing integers with -lt,
> -gt, -eq, -ne, etc. enclosed in [...] test programs (or builtins),
> occasionally quoting (unnecessarily, yes) integer variables, shall
> answer someone who is more conservative than I am. ;-)
--
Chris F.A. Johnson, author <http://cfaj.freeshell.org/shell/>
Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
===== My code in this post, if any, assumes the POSIX locale
===== and is released under the GNU General Public Licence
Yes, that's why I wrote "primarily (but not only)"; the filenames
are, in my experience, the source of 98% of all problems with spaces
in variable values.
>>But using integers the ancient way is nothing I'd nowadays do
>>anyway, if I don't have to do so (maybe because someone holds a
>>gun at your head). Once you're used to $((...)) and ((...)) and
>
> I never use (( ... )); it is not POSIX compliant, and there is no
> advantage to it.
Non-POSIX, true. But I beg to differ WRT being advantageous; writing
if (( expression ))
or
(( x += y * z ))
or
for (( ...;...;... ))
is so convenient, and consistent in syntax, even compared to POSIX'es
$((...)), while calling programs to do the calculation fits the "all
is a command" but is syntactically inferior; but I guess that's also
just a matter of taste.
>>using integer variables even without the $ symbol you don't care
>
> I use $ in arithmetic expressions because there are shells
> that fail if it is not there.
Portability can be an issue, depending on the application context.
Janis
If it has spaces I wouldn't call it an integer. For me an
integer is a variable which has passed the following test
case "$var" in
*[^0-9]* | "" )
# Signal error
;;
* )
# Ok
esac
Or the modified test if you want to allow for a leading sign.
For such a variable I wouldn't use quotes. For one thing writing
quotes is an extra hassle and for another the lack of quotes
serves as a reminder that the variable is not supposed to
contain any special characters.
> > The concern of quoting variables is primarily (but not only) in
> > context of filenames with spaces; this is espacially important
> > if you happen to have to process typical WinDOS filenames or if
> > you stumble across files of someone who stretches the possible
> > Unix filenames to absurdity.
>
> It is not only filenames; it is anywhere that the contents of the
> variable is not guaranteed to be free of spaces.
Which is anywhere that the content of the variable was provided
by input you have no control over. And it's not just spaces but
also characters which are special to the shell.
> > But using integers the ancient way is nothing I'd nowadays do
> > anyway, if I don't have to do so (maybe because someone holds a
> > gun at your head). Once you're used to $((...)) and ((...)) and
>
> I never use (( ... )); it is not POSIX compliant, and there is no
> advantage to it.
How to you increase a counter then ? I do i=$(( $i + 1 ))
I certainly wouldn't want to call an external process every time
I want to increase a counter.
> > using integer variables even without the $ symbol you don't care
>
> I use $ in arithmetic expressions because there are shells
> that fail if it is not there.
>
> > any more about the quote question, in the first place. If you
> > prefer to program "portably", maybe comparing integers with -lt,
> > -gt, -eq, -ne, etc. enclosed in [...] test programs (or builtins),
> > occasionally quoting (unnecessarily, yes) integer variables, shall
> > answer someone who is more conservative than I am. ;-)
I always use [ -gt ] and relatives to do integer comparisons.
POSIX shell syntax is different enough from ALGOL like languages
anyway so [ ] isn't going to make that much of a difference,
we may as well celebrate the shell's individuality !
I quote the controlling variable in a case
statement, never gave me any problems.
I agree.
..
>> I never use (( ... )); it is not POSIX compliant, and there is no
>> advantage to it.
>
> How to you increase a counter then ? I do i=$(( $i + 1 ))
Of course.
> I certainly wouldn't want to call an external process every time
> I want to increase a counter.
I wouldn't dream of it.
> I've often seen the refrain about shell variables
> always being quoted (which I agree with)
> but I've also found instances where they
> cannot (and probably should not) be quoted.
> An example of this is a case statement
> or an if statement where an integer is
> being compared. Doesn't quoting an integer
> make it a string and thus break the compare?
You are confusing compiler quoting with shell quuoting.
When you quote somethign in a compiler, you tell the software that you
are providing a string. The shell doesn't work that way.
Think of shell "quoting" as a flag, per character, to tell the shell if it's
a special character (like '*' OR '?' OR '$') or a character that the
shell treats as a plain character.
So when you quote something, it tells the shell to consider the
characters as typed
Therefore
"a*b"
a"*"b
a\*b
'a*b'
'a''*''b'
\a\*\b
all do the same thing.
Use the echo command to experiment.
echo a*b
will list files that start with a and end with b, because the * is
considered a special character that the shell "globs" into a list of
files mathcing the pattern.
echo "a*b"
treats '*' as a plain character with no special properties (like a and b)
That's the most standard way to do it.[*]
In modern shells I'd just write (in non-POSIX standard way)
(( ++i ))
with no $'s and no explicit assignments for a simple increment.
Janis
> [...]
[*] BTW, are there shells that support $((...)) but require to
prefix 'i' by '$'?
> On 12 Feb, 00:19, "Chris F.A. Johnson" <cfajohn...@gmail.com> wrote:
> > On 2009-02-11, Janis Papanagnou wrote:
> >
> > > Lao Ming wrote:
> > >> I've often seen the refrain about shell variables
> > >> always being quoted (which I agree with)
> > >> but I've also found instances where they
> > >> cannot (and probably should not) be quoted.
> >
> > > Can you give examples?
> >
> > >> An example of this is a case statement
> > >> or an if statement where an integer is
> > >> being compared.
> >
> > > That seems to work for me, both, with quotes or without.
> >
> > >> Doesn't quoting an integer
> > >> make it a string and thus break the compare?
> >
> > > Have you observed such behaviour? Can you give an example?
> >
> > I recall instances in the past where a quoted variable would cause
> > an error in an integer test if it had leading spaces. I can't find
> > any current shell that does that.
>
> If it has spaces I wouldn't call it an integer.
The problem is that some utilities will output results with spaces. For
instance, you'd expect the following to assign an integer to the
variable:
lines=`wc -l < filename`
But see:
echo "|$lines|"
| 5|
So you either have to use this variable unquoted, or remember to strip
the leading spaces off.
--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
A shell which does this when IFS has the default value has a bug
because the behavior is unintuitive *and* violates POSIX.
From http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
After parameter expansion ( Parameter Expansion ),
command substitution ( Command Substitution ), and
arithmetic expansion ( Arithmetic Expansion ), the
shell shall scan the results of expansions and
substitutions that did not occur in double-quotes for
field splitting and multiple fields can result.
The shell shall treat each character of the IFS as a
delimiter and use the delimiters as field terminators
to split the results of parameter expansion and command
substitution into fields.
1. If the value of IFS is a <space>, <tab>, and
<newline>, or if it is unset, any sequence of <space>,
<tab>, or <newline> characters at the beginning or end
of the input shall be ignored and any sequence of those
characters within the input shall delimit a field.
> So you either have to use this variable unquoted, or remember to strip
> the leading spaces off.
Or use a shell which isn't broken.
> On 12 Feb, 21:31, Barry Margolin <bar...@alum.mit.edu> wrote:
> > In article
> > <74cd3a83-cc45-4a46-b420-993922a9b...@t11g2000yqg.googlegroups.com>,
> > Spiros Bousbouras <spi...@gmail.com> wrote:
> >
> > > On 12 Feb, 00:19, "Chris F.A. Johnson" <cfajohn...@gmail.com> wrote:
> >
> > > > I recall instances in the past where a quoted variable would cause
> > > > an error in an integer test if it had leading spaces. I can't find
> > > > any current shell that does that.
> >
> > > If it has spaces I wouldn't call it an integer.
> >
> > The problem is that some utilities will output results with spaces. For
> > instance, you'd expect the following to assign an integer to the
> > variable:
> >
> > lines=`wc -l < filename`
> >
> > But see:
> >
> > echo "|$lines|"
> > | 5|
>
> A shell which does this when IFS has the default value has a bug
> because the behavior is unintuitive *and* violates POSIX.
I did this in bash 3.2.17, but I'm pretty sure I've seen it for many
years in different shells, going back to /bin/sh in SunOS 4.x.
> From http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
>
> After parameter expansion ( Parameter Expansion ),
> command substitution ( Command Substitution ), and
> arithmetic expansion ( Arithmetic Expansion ), the
> shell shall scan the results of expansions and
> substitutions that did not occur in double-quotes for
> field splitting and multiple fields can result.
But it also says:
Each variable assignment shall be expanded for tilde expansion,
parameter expansion, command substitution, arithmetic expansion, and
quote removal prior to assigning the value.
Note that it doesn't say that field splitting happens in variable
assignments.
In fact, if it did what you say, the assignment I wrote would assign a
null string to lines and then try to execute the command "5".
> On 12 Feb, 21:31, Barry Margolin <bar...@alum.mit.edu> wrote:
>> In article
>> <74cd3a83-cc45-4a46-b420-993922a9b...@t11g2000yqg.googlegroups.com>,
>> Spiros Bousbouras <spi...@gmail.com> wrote:
>>
>> > On 12 Feb, 00:19, "Chris F.A. Johnson" <cfajohn...@gmail.com> wrote:
>>
>> > > I recall instances in the past where a quoted variable would cause
>> > > an error in an integer test if it had leading spaces. I can't find
>> > > any current shell that does that.
>>
>> > If it has spaces I wouldn't call it an integer.
>>
>> The problem is that some utilities will output results with spaces. For
>> instance, you'd expect the following to assign an integer to the
>> variable:
>>
>> lines=`wc -l < filename`
>>
>> But see:
>>
>> echo "|$lines|"
>> | 5|
>
> A shell which does this when IFS has the default value has a bug
> because the behavior is unintuitive *and* violates POSIX.
Except POSIX says that word splitting does not happen in variable
assignment, so IFS does not come into play.
>> If it has spaces I wouldn't call it an integer.
>
> The problem is that some utilities will output results with spaces. For
> instance, you'd expect the following to assign an integer to the
> variable:
>
> lines=`wc -l < filename`
>
> But see:
>
> echo "|$lines|"
> | 5|
>
> So you either have to use this variable unquoted, or remember to strip
> the leading spaces off.
Or use echo "|$(($lines))|"
(Perhaps you count that as "stripping the leading spaces off".)
--
Geoff Clare <net...@gclare.org.uk>
> If you can be certain that the variable contains a valid integer,
> and are sure that $IFS does not contain an integer, then there is
> no need to quote it.
You're assuming non-negative integers. If the value can be negative,
you also have to make sure $IFS does not contain a dash (minus sign).
--
Geoff Clare <net...@gclare.org.uk>
There's no need not to quote it either.
Note that $((...)) should be quoted as well as many shells do
word splitting upon arithmetic expansion (as that's required by
POSIX even if that doesn't make any sense).
Basically, that code:
echo $((2 + 3))
works only as expected when $IFS doesn't contain "5", while
echo "$((2 + 3))"
works in any circumstance.
My approach is that in:
echo $((2 + 3))
you're requesting the shell to do word splitting, so it's simply
wrong from a syntax point of view. It's as if in some other
language you wrote: print(split(2 + 3)).
--
Stéphane
> 2009-02-12, 00:19(+00), Chris F.A. Johnson:
> [...]
> > If you can be certain that the variable contains a valid integer,
> > and are sure that $IFS does not contain an integer, then there is
> > no need to quote it.
> [...]
>
> There's no need not to quote it either.
>
> Note that $((...)) should be quoted as well as many shells do
> word splitting upon arithmetic expansion (as that's required by
> POSIX even if that doesn't make any sense).
>
> Basically, that code:
>
> echo $((2 + 3))
>
> works only as expected when $IFS doesn't contain "5", while
Having alphanumeric characters in IFS is incredibly perverse. And it's
not likely to happen without your knowing about it when you're writing
the script. So if you use such a weird IFS then you should be careful
about quoting things that you know a prori are just a single token.
The rest of us will do fine writing $((2 + 3)).
No *need* but not quoting saves typing , increases readibility
and leads to self-documenting code. Furthermore
bash> m=5
bash> echo $(( "$m" ))
bash: "5" : syntax error: operand expected (error token is ""5" ")
dash> m=5
dash> echo $(( "$m" ))
sh: arith: syntax error: " "5" "
> Note that $((...)) should be quoted as well as many shells do
> word splitting upon arithmetic expansion (as that's required by
> POSIX even if that doesn't make any sense).
>
> Basically, that code:
>
> echo $((2 + 3))
>
> works only as expected when $IFS doesn't contain "5", while
>
> echo "$((2 + 3))"
>
> works in any circumstance.
>
> My approach is that in:
>
> echo $((2 + 3))
>
> you're requesting the shell to do word splitting, so it's simply
> wrong from a syntax point of view. It's as if in some other
>
> language you wrote: print(split(2 + 3)).
Only if IFS contains a number.
>> How to you increase a counter then ? I do i=$(( $i + 1 ))
>
> That's the most standard way to do it.[*]
> [*] BTW, are there shells that support $((...)) but require to
> prefix 'i' by '$'?
Old versions of dash. The version in Debian etch requires the $, but
the current version doesn't.
Since dash is based on ash, maybe ash is the same.
--
Geoff Clare <net...@gclare.org.uk>
ash didn't have support for $((...)) as it predates it. It did
have and expr builtin though. debian ash is based on NetBSD sh,
that one being based on ash as in all the other BSDs where sh is
not based on pdksh.
I don't know whether the change that allows variables without $
has made it to NetBSD sh, but a quick read of
http://cvsweb.netbsd.org/bsdweb.cgi/src/bin/sh/arith.y?rev=1.18&content-type=text/x-cvsweb-markup&only_with_tag=MAIN
would seem to indicate it didn't.
Note that $((i * 2)) is not the same as $(($i * 2)) if $i is for
instance "1 + 1" in most shell implementations (the wording is
not clear (to me at least) in POSIX but I beleive the result is
unspecified then anyway for $((i * 2)); it's not clear whether
the output of i=-1; echo $((i * 2)) is specified either though I
wouldn't expect any shell to output anything other than -2 if
they do output anything).
--
Stéphane
>>> [*] BTW, are there shells that support $((...)) but require to
>>> prefix 'i' by '$'?
>>
>> Old versions of dash. The version in Debian etch requires the $, but
>> the current version doesn't.
It's implemented since relase 0.5.5.1 which was published about a month ago
(0.5.5 existed for just one day and 0.5.4 (jul/07) didn't implement it yet,
because the change was checked in shortly after, oct/07).
> ash didn't have support for $((...)) as it predates it. It did
> have and expr builtin though. debian ash is based on NetBSD sh,
> that one being based on ash as in all the other BSDs where sh is
> not based on pdksh.
>
> I don't know whether the change that allows variables without $
> has made it to NetBSD sh, but a quick read of
> http://cvsweb.netbsd.org/bsdweb.cgi/src/bin/sh/arith.y
It's implemented in arith_lex.l (arith_yylex.c in dash).
Thus, FreeBSD implements it since 5.2 (mid '03)
and NetBSD implements it since 3.1/4.0 (early '05)
They all seem to have added it independently.
Next, Debian, Ubuntu and Slackware will inherit from dash; apart
from that I don't know any other ash variant which accepts it.
--
http://www.in-ulm.de/~mascheck/various/ash/
> it's not clear whether
> the output of i=-1; echo $((i * 2)) is specified either
That's a defect which the Austin Group knows about. It should be
fixed in TC1. (There is no formal defect report for it yet - it's
on my to-do list.)
--
Geoff Clare <net...@gclare.org.uk>