Bashed!: Assigning a directory listing to a variable
I want to:
You need to get a directory listing into a variable so you can iterate through it and do things (horrible, unspeakable things) to the child files and directories.
How the hell?
DIRECTORY="/root/example" dirListing=(`ls ${DIRECTORY}`)
WhaaaaaaAAAAA?
We will go over this from the inside out. First, the variable expansion [code]]czoxMjpcIiR7RElSRUNUT1JZfVwiO3tbJiomXX0=[[/code] translates to whatever you have set the variable “DIRECTORY” to. In our example, we’ve set “DIRECTORY” to an example directory I created for this little tutorial:
[root@vps ~]# mkdir example [root@vps ~]# touch example/one [root@vps ~]# touch example/two [root@vps ~]# touch example/three [root@vps ~]# touch example/four
Next, the backticks (or backquotes), eg `…`, tell the processor to treat everything in them as command line text. This is called a command substitution. This means without the backticks, [code]]czoxNTpcImxzICR7RElSRUNUT1JZfVwiO3tbJiomXX0=[[/code] is a string. Inside the backticks, it is a command.
Once the command is run, the results are run through the IFS filter (internal field separator). Since one of the characters assigned by default to the IFS variable (${IFS}) is a space, the spaces in our directory listing become delimiters, and the resulting string is broken up.
So far, we’ve got the command:
dirListing=`ls ${DIRECTORY}`
… and that seems to treat us well. The directory listing is assigned to the [code]]czoxMDpcImRpckxpc3RpbmdcIjt7WyYqJl19[[/code] variable, so you would see something like this:
[root@vps /]# DIRECTORY=/tmp [root@vps /]# dirListing=`ls ${DIRECTORY}` [root@vps /]# echo ${dirListing} four one three two
Notice that the string looks still to be all one line? It isn’t really – try using double quotes and you’ll see how the string is now broken up by the IFS:
[root@vps ~]# echo "${dirListing}" four one three two [root@vps ~]#
So why aren’t we happy yet? Well, if you knew a little bit more about variable expansion in bash, you’d then realize that with the [code]]czo0OlwiZWNob1wiO3tbJiomXX0=[[/code] command, we are technically asking the shell to print out either [code]]czoxMzpcIiR7ZGlyTGlzdGluZ31cIjt7WyYqJl19[[/code] or [code]]czoxNjpcIiR7ZGlyTGlzdGluZ1swXX1cIjt7WyYqJl19[[/code]. The former means the entire string assigned to the dirListing variable, and the latter means the first element of the dirListing array. If we try echoing the first element of an array however, we get this:
[root@vps ~]# echo "${dirListing[0]}" four one three two [root@vps ~]#
The string was broken up, but unless you use double quotes to print it out, you don’t see the LF line breaks, and the entire output was assigned as a long string again – not as the array we are looking for. To get an array, we need to use a subshell. Now the subshell does quite a bit, but we are only interested in one particular effect is has on the output of delimited strings when that output is assigned to a variable. Yes, that is a VERY specific use case of subshell parenthesis! Try this:
[root@vps ~]# (`ls ${DIRECTORY}`) -bash: four: command not found [root@vps ~]#
In my case, “four” is the name of the first file in my “/root/tmp” directory. The subshell tried to execute it, like it is supposed to. If that file had been executable, it would have been run, and then the next file name would have been executed. We aren’t looking for execution though – we want the broken up string assigned out as an array. Let’s run the same command and this time assign the output to our variable…
[root@vps ~]# DIRECTORY="/tmp" [root@vps ~]# dirListing=(`ls ${DIRECTORY}`) [root@vps ~]# echo $dirListing four [root@vps ~]# echo ${dirListing} four [root@vps ~]#
Remember that using the ${…} form of variable designation actually outputs either the value of the variable or the first element of the array (eg: ${…[0]})? Looks like the we got our array output! Let’s check the next few elements to make sure:
[root@vps ~]# echo ${dirListing[1]} one [root@vps ~]# echo ${dirListing[2]} three [root@vps ~]# echo ${dirListing[3]} two [root@vps ~]#
See? That wasn’t so hard, was it?