Friday, November 03, 2006

'bash'ing!

I love bash. I absolutely love it. It is fun. It is great fun! Take this simple script, posted by GreyCat in #bash for example:

x="hello world"; echo "$x" | read a b; echo "$a $b"; read a b <<< "$x"; echo "$a $b"

Quite simple, isn't it? Well, here's the output:


hello world

Hmm? OK. Let's try again.

hello world
hello world

What's going on?

OK. Now here's the beauty of this little script. It teaches so many fundamentals of bash.

We start off with a simple x="hello world". Next we have a pipeline. A pipe feeds the standard output of one command to the standard input of another command, as we know.

So here, we have the standard output of echo, which is 'hello world' (Well, that's written in English. In bash's terms, the output is equivalent to "hello" "world" I suppose..), being fed as the standard input of read. read stores the two words into two variables, a and b.

The pipeline finishes there and then we simply echo the values of a and b. The output, as we can see, is blank.

Now why exactly? Let's check.. Is the assignment of the variables correct? Yes. read takes the standard input by default, so a and b get assigned the values hello and world respectively. But the output of echo is still blank.

Why?

The answer is subshell. A pipeline spawns a different subshell for each process. So read a b operates in a different subshell.. different from echo "$a $b". As we know, subshells cannot propagate any information back to its parent shell. Hence, the values of a and b are blank, as they don't yet exist in the parent shell.

In the second case, we've used a form of here document - <<<. <<< expands the argument "$x" and feeds it to read a b's standard input. This time, we get a proper hello world output from echo "$a $b", because <<< doesn't spawn a subshell.

Now, if you run the same command line again, in the same session, you'll get this output:

hello world
hello world

How come?

Quite simple. The values of a and b are set by our previously run read a b <<< "$x". The values already exist in our shell, hence.

I suppose power users will find this information quite rudimentary. But, newbies would do well to understand the concepts involved. No matter how good I may become at bash, such small concepts will always be fascinating!

3 comments:

fasel said...

it doenst work on my system.
which bash-version are you using?

i got app-shells/bash-3.1_p17 and i get an error from read:

-bash: read: `hello world': not a valid identifier

floyd_n_milan said...

Do not echo "$x" as the here string to read. Use just "$x".

Nikola said...

Statistically, the safest form for of travel (miles travelled versus number of deaths) is the elevator.notebook review