Sunday, April 16, 2006

Bash : Order of expansions

This one is an important thing to understand for anyone who wants to know how bash works.
So here is a refresher, this is the order of expansions:
* brace expansion
* tilde expansion
* parameter and variable expansion
* command substitution
* arithmetic expansion
* word splitting
* filename expansion
Now here is what i am going to do,go through all of these and actually see if they work as they should.
First lets check the first two : brace expansion and tilde expansion
kalyan@thunderbird:~$ echo ~ #tilde expansion:current users homedir
/home/kalyan
kalyan@thunderbird:~$ echo ~b
~b
#tilde expansion fails: no user with name b
kalyan@thunderbird:~$ echo ~kalyan
/home/kalyan
#tilde expansion works and gives kalyan user's home dir
kalyan@thunderbird:~$ echo a{b,,c} #brace expansion
ab a ac
kalyan@thunderbird:~$ echo ~{b,,kalyan} #test to see who comes first
~b /home/kalyan /home/kalyan
kalyan@thunderbird:~$ echo /home/kalyan{b,,kalyan}
/home/kalyanb /home/kalyan /home/kalyankalyan
#brace expansion first as otherwise we'd get

Now time for parameter and variable expansion. This is simple to check we add a variable

kalyan@thunderbird:~$ myvar=kalyan
kalyan@thunderbird:~$ echo $myvar
kalyan
kalyan@thunderbird:~$ echo ~{b,,$myvar}
~b /home/kalyan ~$myvar
#strange, no variable expansion
kalyan@thunderbird:~$ echo ~{b,,"$myvar"}
~b /home/kalyan ~kalyan
#variable expansion but only after tilde expansion

So we need to enclose the variable in quotes to force bash to expand in this scenario.
Okay lets move on to command substitution now

kalyan@thunderbird:~$ cat > myfile
kalyan
#create a file with contents as my name
kalyan@thunderbird:~$ cat myfile #
kalyan
kalyan@thunderbird:~$ myvar1=myfile
#create a variable with value myfile
kalyan@thunderbird:~$ cat $myvar1
kalyan
kalyan@thunderbird:~$ echo $(cat $myvar1)
kalyan
#shows myvar1 is expanded before command substitution
kalyan@thunderbird:~$ echo ~{b,,$(cat $myvar1)}
~b /home/kalyan ~$(cat $myvar1)
#so no var expansion or command substitution
kalyan@thunderbird:~$ echo ~{b,,"$(cat $myvar1)"}
~b /home/kalyan ~kalyan
#we put quotes and now it works

So that proved that command substitution follows variable/parameter expansion. Now its arithmetic expansion

kalyan@thunderbird:~$ echo $(( 5 + 5 )) #arithmetic expansion
10
kalyan@thunderbird:~$ cat > five
5
kalyan@thunderbird:~$ cat five
5
kalyan@thunderbird:~$ echo $(( $(cat five) + $(cat five) ))
10
#we should get 10. :)

That was neat. wasnt it :)..now time to get little insane. Bash splits words using the characters in IFS as the seperator so lets engineer an example to prove that word splitting happens after arithmetic expansion ;)

kalyan@thunderbird:~$ echo $(( 101010101 + 202020202 ))
303030303
kalyan@thunderbird:~$ OFS=$IFS #save the IFS
kalyan@thunderbird:~$ IFS=3 #change it
kalyan@thunderbird:~$ echo $(( 101010101 + 202020202 ))
0 0 0 0
#wow where did the 3's go, they were removed during word splitting :)
kalyan@thunderbird:~$ IFS=$OFS #back to sanity

Now we are onto the last expansion and thats filename expansion. bash actually looks for files to expand '*','?'.

kalyan@thunderbird:~/fun$ cat > 10_file_name_starts_with_ten
hmm i am tired of bash expansions now :)
kalyan@thunderbird:~/fun$ echo 10*
10_file_name_starts_with_ten
kalyan@thunderbird:~/fun$ IFS=2 #for the example below
kalyan@thunderbird:~/fun$ echo $(( 30*7 ))*
10_file_name_starts_with_ten
#30*7 expands to 210 then bash removes '2' because of word splitting,that leaves us with 10* which undergoes filename expansion ..so simple :P
kalyan@thunderbird:~/fun$ IFS=$OFS #restore sanity

Thats it and i really mean it when i say hmm i am tired of bash expansions now :)

0 Comments:

Post a Comment

<< Home