Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

All files in one dir, linux

Tags:

linux

bash

Today I tried a script in linux to get all files in one dir. It was pretty straightforward, but I found something interesting.

 #!/bin/bash
InputDir=/home/XXX/
for file in $InputDir'*'
do
  echo $file
done

The output is:

/home/XXX/fileA /home/XXX/fileB 

But when I just input the dir directly, like:

 #!/bin/bash
InputDir=/home/XXX/
for file in /home/XXX/*
do
  echo $file
done

The output is:

/home/XXX/fileA
/home/XXX/fileB

It seems, in the first script, there was only one loop and all the file names were stored in the variable $file in the FIRST loop, separated by space. But in the second script, one file name was stored in $file just in one loop, and there were more than one loop. What is exactly the difference between these two scripts?

Thanks very much, maybe my question is a little bit naive..

like image 857
penpen926 Avatar asked Dec 08 '22 16:12

penpen926


2 Answers

The behavior is correct and "as expected".

for file in $InputDir'*' means assign "/home/XXX/*" to $file (note the quotes). Since you quoted the asterisk, it will not be executed at this time. When the shell sees echo $file, it first expands the variables and then it does glob expansion. So after the first step, it sees

echo /home/XXX/*

and after glob expansion, it sees:

echo /home/XXX/fileA /home/XXX/fileB

Only now, it will execute the command.

In the second case, the pattern /home/XXX/* is expanded before the for is executed and thus, each file in the directory is assigned to file and then the body of the loop is executed.

This will work:

for file in "$InputDir"*

but it's brittle; it will fail, for example, when you forget to add a / to the end of the variable $InputDir.

for file in "$InputDir"/*

is a little bit better (Unix will ignore double slashes in a path) but it can cause trouble when $InputDir is not set or empty: You'll suddenly list files in the / (root) folder. This can happen, for example, because of a typo:

inputDir=...
for file in "$InputDir"/*

Case matters on Unix :-)

To help you understand code like this, use set -x ("enable tracing") in a line before the code you want to debug.

like image 75
Aaron Digulla Avatar answered Dec 11 '22 09:12

Aaron Digulla


The difference is the quoting of '*'. In the first case the loop only executes once, with $file equal to /home/XXX/* which then expands to all the files in the directory when passed to echo. In the second case it executes once per file, with $file equal to each file name in turn.

Bottom line - change:

for file in $InputDir'*'

to:

for file in $InputDir*

or, better, and to make it more readable - change:

InputDir=/home/XXX/
for file in $InputDir'*'

to:

InputDir=/home/XXX
for file in $InputDir/*
like image 33
Paul R Avatar answered Dec 11 '22 08:12

Paul R