Search code examples
bashfor-loopls

Check for readable files for a directory in bash


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?


Solution

  • 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.