I'm taking a Unix class, and here's a part of my assignment:
For each file and subdirectory in the user’s ~/Documents directory, determine if the item is a file or directory, and display a message to that effect, using the file name in the statement.
So, what I have written is this:
docs=`ls ~/Documents`
for file in $docs ; do
if [ -f $file ] ; then
echo $file "is a file."
elif [ -d $file ] ; then
echo $file "is a directory."
else
echo $file "is not a file or directory."
fi
done
My Documents directory includes these files and directories:
DocList.txt (file)
Letter (file)
mypasswdfile (file)
samples (directory)
things (directory)
touchfile (file)
So I figured that the output should be this:
DocList.txt is a file.
Letter is a file.
mypasswdfile is a file.
samples is a directory.
things is a directory.
touchfile is a file.
However, this is the output:
DocList.txt is not a file or directory.
Letter is not a file or directory
mypasswdfile is not a file or directory
samples is not a file or directory
things is not a file or directory
touchfile is not a file or directory
I feel like I should mention that if I set the $docs variable to `ls ~' it will successfully display the contents of my home directory and whether the items are files or directories. This does not work with other paths I have tried.
Your problem is that ls
only outputs the file names without path.
So your $file
gets the values
DocList.txt
Letter
mypasswdfile
samples
things
touchfile
from loop run to loop run.
If your current directory is NOT ~/Documents
, testing these file names is wrong, as this would search in the current directory and not in the intended one.
A much better way to accomplish your task is
for file in ~/Documents/* ; do
...
done
which will set $file
to each of the full path names needed to find your file.
After doing so, it should work, but it is very error prone: once your path or one of your files starts having a space or other blank character in it, it will fall on your feet.
Putting "
around variables which can potentially contain something with a space etc. is quite essential. There is almost no reason ever to use a variable without its surrounding "
.
What is the difference here?
With [ -f $file ]
, and file='something with spaces'
, [
is called with the arguments -f
, something
, with
, spaces
and ]
. This surely leads to wrong behaviour.
OTOH, with [ -f "$file" ]
, and file='something with spaces'
, [
is called with the arguments -f
, something with spaces
and ]
.
So quoting is very essential in shell programming.
Of course, the same holds for [ -d "$file" ]
.
The problem is your ls
command - you're treating the output of ls
as absolute e.g. /home/alex/Documents/DocList.txt
, but when you do ls ~/Documents
it prints out DocList.txt
(a relative file path / name).
To get the expected absolute behaviour you can use the find
command instead:
docs=`find ~/Documents`
As mentioned in the comments and in another answer, to also be able to handle whitespace in filenames you need to do something like:
docs=( ~/Documents/* )
for f in "${docs[@]}"; do
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With