I'm new with Bash scripting and I've been playing around with it, but I have this script that I doesn't understand:
#!/bin/bash
for name in $(ls $HOME)
do
if [ -f $name -a -r $name ]
then
echo "$name is file"
fi
done
If I run it, it prints nothing. I'm pretty sure that in my home directory I have readable files. Ex:
-rw-r--r-- 1 user user 368 feb 17 22:39 requirements.txt
If I test it with another directory, it tells me that I have two files that are readable:
-rwxr-xr-x 1 user user 442 jul 27 23:47 longest-and-shortest-username.sh
-rwxr-xr-x 1 user user 1155 jul 28 00:39 options-for-files-in-directory.sh
My Bash version is: 4.2.45(1)-release
Am I loosing something?
The code was trying to get names of files in the HOME directory. But, it was then testing if that name existed in the current directory (which must have been different).
The solution is to attach the directory to the file name. Try:
for name in "$HOME"/*
do
if [ -f "$name" -a -r "$name" ]
then
echo "$name is file"
fi
done
The above has the additional advantage that it will work for file names with spaces and all manor of other hostile characters.
When bash
sees $(ls $HOME)
, it runs ls $HOME
and then applies word splitting to the results. So, if you have a file named my file
, bash
would split it into two arguments my
and file
. You don't want this. By contrast, when bash
sees $HOME/*
, it returns all the file names un-mangled.
Note also that I put double-quotes around $name
in [ -f "$name" -a -r "$name" ]
. This prevents word splitting and assures that this test works properly for all file names.