Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

As a primarily Java programer, I find the bash if-then construct quite confusing, especially regarding whitespace. Can anyone explain, why the first one works but not the second and third?

#works
if [ -n $1 ]; then echo "parameterized"; fi

#output: ./links: Zeile 1: [-n: Kommando nicht gefunden.
if [-n $1 ]; then echo "parameterized"; fi

#output: ./links: Zeile 1: [: Fehlende `]'
if [ -n $1]; then echo "parameterized"; fi
share|improve this question
3  
Leaving a variable unquoted is the split+glob operator in shells. There are very few cases where you really want to leave variables unquoted. –  Stéphane Chazelas Feb 28 at 11:30
add comment

2 Answers 2

up vote 3 down vote accepted

The inconsistency is largely due to historical reasons.

The use of brackets as the conditional command came after the use of brackets in wildcard patterns. So at the time [ -n foo ] came onto the scene, [foo] already meant “a file whose name is f or o”. While few uses of the brackets operator in practice would have conflicted with realistic uses of the brackets in wildcards, the authors chose not to risk breaking existing scripts by changing the syntax. This design choice also made implementation easier: initially [ was implemented as an external command, which couldn't have been done if the space after [ had been optional. (Modern systems still have [ as an external command but almost all modern shells also have it built in.)

For similar reasons, your “working” code is actually incorrect in most circumstances. $1 does not mean “the value of parameter 1”: it means “take the value of parameter 1, split it into separate words at whitespace (or whatever the value of IFS is), and interpret each word as a glob pattern”. The way to write “the value of parameter 1” requires double quotes: "$1". See When is double-quoting necessary? for the nitty-gritty. You don't need to understand this; all you need to remember is: always put double quotes around variable substitutions "$foo" and command substitutions "$(foo)". Thus:

if [ -n "$1" ]; then …

In bash, ksh and zsh, but not in plain sh, you can also use double brackets. Single brackets [ … ] are parsed like an ordinary command (and indeed [ is an ordinary command, albeit usually built in). Double brackets are a separate syntactic construct and you can omit the double quotes most of the time.

if [[ -n $1 ]]; then …

However, there is an exception: [[ "$foo" = "$bar" ]] to test if the two variables have the same value requires double quotes around $bar, otherwise $bar is interpreted as a wildcard pattern. Again, rather than remember the details, you might as well use double quotes all the time.

share|improve this answer
add comment

in fact the character [ is a built-in shell command that evaluate argument until the argument ]
bash use argument separate by space so if you want to call [ you need to put a space or it will try to execute the command [-n which is not a function or binary bash know (at least until you create one yourself).

When you write [-n $1 ] it means
[-n with arguments $1 and ] which make no sense
and if you put [ -n $1] it means
[ with argument -n and $1] but missing the ] argument of your function [ so it can't evaluate your expression

share|improve this answer
    
Hm, I've been using it for years, never thought of why it's this way and not any other. This makes total sense. Thank you for education. –  Marcin Feb 28 at 14:23
    
@Marcin I often asked myself the question and I recently read a create answer about where is cd ? and then I understand why a space was an obligation, because without it make no sense :D anyway I'm glad this help you –  Kiwy Feb 28 at 14:26
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.