[ "$#" != "1" ] vs [ $# != 1 ]

26 views
Skip to first unread message

hongy...@gmail.com

unread,
May 11, 2022, 2:31:40 AMMay 11
to
I noticed the following example here [1]:

```
#!/bin/sh

if [ "$#" != "1" ]; then
echo "Usage: test.sh <string>"
exit 1
fi;

gap -r -b -q << EOI
LoadPackage( "CrystCat" );
DisplaySpaceGroupType( "$1" );
EOI
```

It seems that [ $# != 1 ] is enough. Why use [ "$#" != "1" ] here?

[1] https://stackoverflow.com/questions/13418849/how-can-i-call-gap-functions-from-a-shell-script

Regards,
HZ

Chris Elvidge

unread,
May 11, 2022, 8:07:26 AMMay 11
to
Why not try [ $# -ne 1 ] ?

--
Chris Elvidge
England

Lew Pitcher

unread,
May 11, 2022, 8:10:49 AMMay 11
to
On Tue, 10 May 2022 23:31:37 -0700, hongy...@gmail.com wrote:

> I noticed the following example here [1]:
>
> ```
> #!/bin/sh
>
> if [ "$#" != "1" ]; then
> echo "Usage: test.sh <string>"
> exit 1
> fi;
>
> gap -r -b -q << EOI LoadPackage( "CrystCat" );
> DisplaySpaceGroupType( "$1" );
> EOI ```
>
> It seems that [ $# != 1 ] is enough. Why use [ "$#" != "1" ] here?

I see no /obvious/ reason.

On a (perhaps) related note, why did the author of that code snippet
use a string test rather than an an arithmetic test? To me, the
code snippet should read
if [ $# -ne 1 ]
then
echo 'Usage: test.sh <string>'
exit 1
fi

--
Lew Pitcher
"In Skills, We Trust"

Kees Nuyt

unread,
May 11, 2022, 8:17:08 AMMay 11
to
On Tue, 10 May 2022 23:31:37 -0700 (PDT), "hongy...@gmail.com"
<hongy...@gmail.com> wrote:

> I noticed the following example here [1]:
>
> ```
> #!/bin/sh
> if [ "$#" != "1" ]; then
> echo "Usage: test.sh <string>"
> exit 1
> fi;
>
> It seems that [ $# != 1 ] is enough. Why use [ "$#" != "1" ] here?

Both are possible. If they had written:
:: [ $# != 1 ]
you might have asked:
:: It seems that [ "$#" != "1" ] is enough.
:: Why use [ $# != 1 ] here?

Not surprisingly, there is even another way to do it:
:: [ $# -ne 1 ]

I hope this helps
--
Kees Nuyt

Janis Papanagnou

unread,
May 11, 2022, 9:08:57 AMMay 11
to
On 11.05.2022 08:31, hongy...@gmail.com wrote:
> I noticed the following example here [1]:
>
> ```
> #!/bin/sh
>
> if [ "$#" != "1" ]; then
> echo "Usage: test.sh <string>"
> exit 1
> fi;
>
> gap -r -b -q << EOI
> LoadPackage( "CrystCat" );
> DisplaySpaceGroupType( "$1" );
> EOI
> ```

Why did you post this here-doc code which is completely unrelated
to your question?

>
> It seems that [ $# != 1 ] is enough. Why use [ "$#" != "1" ] here?

On Stackoverflow I experienced a couple of "experts" that spread
the wisdom of "always quote variable expansions"; this is fine as
a rule of thumb (but annoying if you know when you need quotes and
when not). This may have been the reason but is of course completely
unnecessary.

Since the shebang line is qualifying '/bin/sh' the best answer (as
already suggested) is probably to use [ $# -ne 1 ]

Janis

Kenny McCormack

unread,
May 11, 2022, 12:29:02 PMMay 11
to
In article <t5g944$3ak$1...@dont-email.me>,
Lew Pitcher <lew.p...@digitalfreehold.ca> wrote:
...
>I see no /obvious/ reason.
>
>On a (perhaps) related note, why did the author of that code snippet
>use a string test rather than an an arithmetic test? To me, the
>code snippet should read

Like you said above, there is no difference.

And there are about thousand other ways of doing it as well. Take your pick...

--
The randomly chosen signature file that would have appeared here is more than 4
lines long. As such, it violates one or more Usenet RFCs. In order to remain
in compliance with said RFCs, the actual sig can be found at the following URL:
http://user.xmission.com/~gazelle/Sigs/Rorschach

hymie!

unread,
May 11, 2022, 3:49:49 PMMay 11
to
In our last episode, the evil Dr. Lacto had captured our hero,
hongy...@gmail.com <hongy...@gmail.com>, who said:
> I noticed the following example here [1]:
>
> if [ "$#" != "1" ]; then
>
> It seems that [ $# != 1 ] is enough. Why use [ "$#" != "1" ] here?

Consider a different variable

if [ $FOO != 1 ] ; then

if $FOO is completely uninitialized, then this will expand to

if [ != 1 ] ; then

which is a syntax error.

That is the reason that I, personally, almost always use the extra
quotation marks.

--hymie! http://nasalinux.net/~hymie hy...@nasalinux.net

hongy...@gmail.com

unread,
May 11, 2022, 9:35:27 PMMay 11
to
As commented by others in this thread, the following method will avoid this problem?

[ $# -ne 1 ]

>
> --hymie! http://nasalinux.net/~hymie hy...@nasalinux.net

Janis Papanagnou

unread,
May 11, 2022, 9:53:39 PMMay 11
to
$FOO is an arbitrary user defined (or undefined) variable.
$# is a numeric variable set by the shell.

So [ $FOO -ne 1 ] will not avoid the issue.

Of course just trying that code would be faster than writing a post.

>
>>
>> --hymie! http://nasalinux.net/~hymie hy...@nasalinux.net

hongy...@gmail.com

unread,
May 11, 2022, 11:42:17 PMMay 11
to
Yes. All the problems discussed in this post can be illustrated by the following examples:

$ [ "$FOO" = 1 ]; echo $?
1
$ [ "$FOO" = "1" ]; echo $?
1
$ [ $FOO -ne 1 ]
bash: [: -ne: unary operator expected
$ [ "$FOO" -ne 1 ]
bash: [: : integer expression expected

But maybe this way can also help others.

Best,
HZ

> >
> >>
> >> --hymie! http://nasalinux.net/~hymie hy...@nasalinux.net

Lew Pitcher

unread,
May 12, 2022, 10:21:29 AMMay 12
to
As a specific solution, yes.

$# is guaranteed to contain a numeric count of the number of arguments
passed into a script. It *cannot* be empty, or contain space delimited
values, so bracketing it in doublequotes is redundant. Both sides of the
test contain a decimal values, so a numeric test (such as -ne) would be
appropriate.

OTOH, as a general solution, not so much.

In the test
[ $FOO -ne $BAR ]
neither $FOO nor $BAR provide the content guarantees that $# does (not
empty, not space delimited string, numeric value only) so it would be
prudent to bracket each with doublequotes. Also, given that neither
guarantees a numeric value, it would be prudent to use the != test
instead of the -ne test, making the /prudent/ test
[ "$FOO" != "$BAR" ]

Janis Papanagnou

unread,
May 12, 2022, 6:59:15 PMMay 12
to
In your thread you have asked a question about using the test command
and quoting to address some issues and, based on some sample code from
the net, understand how it works best. In this context it is noteworthy
that (for own programs) you have more (and better) choices. Some of the
issues and caveats that the historic test command and shell's command
syntax with test has (which unfortunately is also the only standard
base for standard shell) are fixed or alleviated with the test syntax
[[...]] that the powerful "modern" shells (ksh, bash, zsh, maybe others
too) support. (In this vein inspect for arithmetic contexts also the
arithmetic command ((...)) construct.)

I suggest to try these contemporary constructs with code samples like
the ones you started with above, vary the data from undefined, empty,
defined, defined with spaces, use of shell-patterns for comparisons,
use various comparison operators (!=, ==, =) etc., compare it with the
old (standard) syntax, and observe the difference in behavior, the
consistency, whether it meets your expectations, or whether one or the
other surprises you. Then draw your conclusions.

Janis

hongy...@gmail.com

unread,
May 12, 2022, 8:59:21 PMMay 12
to
Thank you for your advice and suggestions.

> Janis
HZ

hongy...@gmail.com

unread,
May 12, 2022, 9:01:27 PMMay 12
to
Thank you for your prudent analysis.

Geoff Clare

unread,
May 13, 2022, 8:41:08 AMMay 13
to
Lew Pitcher wrote:

> $# is guaranteed to contain a numeric count of the number of arguments
> passed into a script. It *cannot* be empty, or contain space delimited
> values, so bracketing it in doublequotes is redundant.

Double quotes around $# are redundant only if there are no digits in IFS.

That would certainly be true for the case the OP asked about, where the
$# expansion was in the first command executed in the script. But it
can't be assumed to be true in general.

--
Geoff Clare <net...@gclare.org.uk>

Lew Pitcher

unread,
May 13, 2022, 10:14:39 AMMay 13
to
On Fri, 13 May 2022 13:21:52 +0100, Geoff Clare wrote:

> Lew Pitcher wrote:
>
>> $# is guaranteed to contain a numeric count of the number of arguments
>> passed into a script. It *cannot* be empty, or contain space delimited
>> values, so bracketing it in doublequotes is redundant.
>
> Double quotes around $# are redundant only if there are no digits in
> IFS.

Good catch!

>
> That would certainly be true for the case the OP asked about, where the
> $# expansion was in the first command executed in the script. But it
> can't be assumed to be true in general.




--

Kaz Kylheku

unread,
May 13, 2022, 10:24:09 AMMay 13
to
IFS is analogous to an important environmental register in a machine
language ABI, such as a global offset pointer register. Code which wants
to manipulate it must save the value, and restore it not only when it
is done, but around calls to any other code.

The onus is on whoever introduces IFS manipulation to do the above,
and in general to debug their shit. We'd never blame a piece of shell
code which does a naked $# expansion for a breakage caused by an altered
IFS; the IFS alteration is to blame.

If you're writing code with unknown callers for general use, you should
cheerfully assume that the normal IFS is in effect, and not do any
obviously unnecessary quoting.

Only code which is specifically a helper routine to some
IFS-manpipulating code (like being part of the same module) has any
reason to defend against the changed IFS.

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

hongy...@gmail.com

unread,
May 15, 2022, 1:15:44 AMMay 15
to
On Friday, May 13, 2022 at 8:41:08 PM UTC+8, Geoff Clare wrote:
> Lew Pitcher wrote:
>
> > $# is guaranteed to contain a numeric count of the number of arguments
> > passed into a script. It *cannot* be empty, or contain space delimited
> > values, so bracketing it in doublequotes is redundant.
> Double quotes around $# are redundant only if there are no digits in IFS.

It's empty on my machine (Ubuntu 20.04.3 LTS):

$ echo $IFS

$

Kees Nuyt

unread,
May 15, 2022, 4:57:34 AMMay 15
to
On Sat, 14 May 2022 22:15:41 -0700 (PDT), "hongy...@gmail.com"
<hongy...@gmail.com> wrote:

> It's empty on my machine (Ubuntu 20.04.3 LTS):
>
> $ echo $IFS
>
> $

No, it isn't empty. The characters it contains just do not leave
ink on your canvas.

user@host:~ $ printf '>%s<' "$IFS"|hexdump -C
00000000 3e 20 09 0a 3c |> ..<|
00000005
--
Kees Nuyt

hongy...@gmail.com

unread,
May 15, 2022, 9:31:55 AMMay 15
to
I get the following using od:

$ printf '>%s<' "$IFS"| od -xc --endian=big
0000000 3e20 090a 3c00
> \t \n <
0000005

Why aren't they exactly the same?

HZ

Janis Papanagnou

unread,
May 15, 2022, 9:58:36 AMMay 15
to
The output isn't the same because you used a different program.

The IFS value is the same. Of course the unnecessary > and < will
distract you from the IFS dedails in the od/hexdump output. Keep
it simple

$ printf '%s' "$IFS" | od -t x1
0000000 20 09 0a

That's a Blank, a Tab, and a Newline.

Janis

>
> HZ
>

hongy...@gmail.com

unread,
May 16, 2022, 5:00:31 AMMay 16
to
I checked them with the following command:

$ ascii -t 0x20 0x09 0x0a
2/0 32 0x20 0o40 00100000
0/9 9 0x09 0o11 00001001
0/10 10 0x0A 0o12 00001010

How to retrieve the character names at the same time?

HZ

Kees Nuyt

unread,
May 16, 2022, 5:29:42 AMMay 16
to
On Mon, 16 May 2022 02:00:27 -0700 (PDT), "hongy...@gmail.com"
<hongy...@gmail.com> wrote:

>
> I checked them with the following command:
>
> $ ascii -t 0x20 0x09 0x0a
> 2/0 32 0x20 0o40 00100000
> 0/9 9 0x09 0o11 00001001
> 0/10 10 0x0A 0o12 00001010
>
> How to retrieve the character names at the same time?

1: Explore the options in 'man -s 1 ascii' and try
ascii -a 0xHH ...
plus a bit of awk code

2: You don't have to, because from experience you know
0x20 is space, 0x09 is TAB and 0x0A is linefeed

3: Use the lookup table in 'man -s 7 ascii'

You just failed the quiz.
--
Kees Nuyt

hongy...@gmail.com

unread,
May 17, 2022, 1:22:24 AMMay 17
to
On Monday, May 16, 2022 at 5:29:42 PM UTC+8, Kees Nuyt wrote:
> On Mon, 16 May 2022 02:00:27 -0700 (PDT), "hongy...@gmail.com"
> <hongy...@gmail.com> wrote:
>
> >
> > I checked them with the following command:
> >
> > $ ascii -t 0x20 0x09 0x0a
> > 2/0 32 0x20 0o40 00100000
> > 0/9 9 0x09 0o11 00001001
> > 0/10 10 0x0A 0o12 00001010
> >
> > How to retrieve the character names at the same time?
> 1: Explore the options in 'man -s 1 ascii' and try
> ascii -a 0xHH ...
> plus a bit of awk code

$ echo "0x20 0x09 0x0a" | xargs -n1 ascii -a|grep names
Other names: Space, Blank
Other names: Horizontal Tab, \t
Other names: Newline, \n
Reply all
Reply to author
Forward
0 new messages