LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (http://www.linuxquestions.org/questions/linux-general-1/)
-   -   Bash mini quiz. (http://www.linuxquestions.org/questions/linux-general-1/bash-mini-quiz-4175446003/)

jschiwal 01-17-2013 07:22 AM

Bash mini quiz.
 
This isn't a question but a one question quiz.

Suppose you have two directories, dir1 and dir2.
Dir1 has three files in it: song1.mp3, song2.mp3 and song3.mp3.
Dir2 has three files in it: song4.mp3, song5.mp3 and song6.mp3.

Inside dir1, enter the command "songlist=*.mp3".
"echo $songlist" displays "song1.mp3 song2.mp3 song3.mp3".

Now cd into dir2.
What does "echo $songlist" show?
song1.mp3 song2.mp3 song3.mp3
or
song4.mp3 song5.mp3 song6.mp3

bijo505 01-17-2013 07:41 AM

Obviously song4.mp3 song5.mp3 song6.mp3... because we assigned the variable using wildcard * ;-)

TobiSGD 01-17-2013 07:43 AM

Not so obvious as you think. We never assigned the wildcard to the variable, it was expanded to the actual filenames by the shell before the assignment took place.
So it will show "song1.mp3 song2.mp3 song3.mp3", since this is what was assigned to the variable.

bijo505 01-17-2013 08:00 AM

Quote:

Originally Posted by TobiSGD (Post 4872095)
Not so obvious as you think. We never assigned the wildcard to the variable, it was expanded to the actual filenames by the shell before the assignment took place.
So it will show "song1.mp3 song2.mp3 song3.mp3", since this is what was assigned to the variable.

Hi TobiSGD,

Hmm!! got confused... to clear this I tested that and what I said is correct..... If you run echo $songlist from any other dir, it will show *.mp3

colucix 01-17-2013 08:03 AM

Quote:

Originally Posted by TobiSGD (Post 4872095)
Not so obvious as you think. We never assigned the wildcard to the variable, it was expanded to the actual filenames by the shell before the assignment took place.

Nope. Otherwise the resulting command line would throw a command not found error:
Code:

$ songlist=song1.mp3 song2.mp3 song3.mp3
bash: song2.mp3: command not found

There should be an exception to filename expansion in variable assignment. Diggin' into it... :scratch:

colucix 01-17-2013 08:14 AM

From the Bash reference manual:
Quote:

A variable may be assigned to by a statement of the form

name=[value]

If value is not given, the variable is assigned the null string. All values undergo tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, and quote removal (detailed below). If the variable has its integer attribute set, then value is evaluated as an arithmetic expression even if the $((…)) expansion is not used (see Arithmetic Expansion). Word splitting is not performed, with the exception of "$@" as explained below. Filename expansion is not performed. Assignment statements may also appear as arguments to the alias, declare, typeset, export, readonly, and local builtin commands.
;)

TobiSGD 01-17-2013 08:22 AM

OK, I stand corrected, bijo505 and colucix are right, I just tested it:
Code:

bash-4.2$ ls dir1 dir2
dir1:
song1.mp3  song2.mp3  song3.mp3

dir2:
song4.mp3  song5.mp3  song6.mp3
bash-4.2$ cd dir1
bash-4.2$ songlist=*.mp3
bash-4.2$ echo $songlist
song1.mp3 song2.mp3 song3.mp3
bash-4.2$ cd ../dir2
bash-4.2$ echo $songlist
song4.mp3 song5.mp3 song6.mp3

You never stop learning with Linux.

Fun fact: I tried this first in Zsh, this is what I got:
Code:

tobi dir1 ☺ $ songlist=*.mp3
tobi dir1 ☺ $ echo $songlist
*.mp3


colucix 01-17-2013 09:42 AM

In zsh:
Code:

$ setopt globassign
$ songlist=*.mp3
$ echo $songlist
song1.mp3 song2.mp3 song3.mp3

In this case it is the actual and only value of the variable, so that moving to Dir2 the value is the same. On the contrary if you assign the option globsubst, you get the same behaviour described previously, since the filename expansion is performed upon the variable evaluation (not upon the assignment).

TobiSGD 01-17-2013 09:52 AM

Thanks for the clarification.

chrism01 01-17-2013 09:15 PM

I tested it in bash (default settings on Centos6) and got the list of files for whichever dir I was in.
IOW, the effect is that it 'stores' the wildcard string, but when you 'echo' the var, it effectively 'eval's it and matches the current dir content.

I must admit originally I guessed it would store the first input: wrong ;)

jschiwal 01-17-2013 11:37 PM

Since arguments are evaluated by bash before a command runs, I was surprised when I noticed this late binding. I was doing something like "for file in ${filelist}; ..."

If you export the variable and run "env | grep songlist" the result is *.mp3.

Now for extra credit, try "songlist=(*.mp3)"
You can use "echo ${songlist[*]}" to display the contents of a bash array.


All times are GMT -5. The time now is 11:36 PM.