3

(This is debian squeeze amd64)

I need to test if a file is a member of a list of files. So long my (test) script is:

set -x
array=$( ls )
echo $array
FILE=log.out
# This line gives error!
if $FILE in $array
then   echo "success!"
else  echo "bad!"
fi
exit 0

¿Any ideas?

Thanks for all the responses. To clarify: The script given is only an example, the actual problem is more complex. In the final solution, it will be done within a loop, so I need the file(name) to be tested for to be in a variable.

Thanks again. No my test-script works, and reads:


  in_list() {
       local search="$1"
       shift
       local list=("$@")
       for file in "${list[@]}" ; do
           [[ "$file" == "$search" ]] && return 0
       done
       return 1
    }
    #
    # set -x
    array=( * )  # Array of files in current dir
    # echo $array
    FILE="log.out"
    if in_list "$FILE" "${array[@]}" 
    then   echo "success!"
    else  echo "bad!"
    fi
    exit 0
  • 4
    You should [never](http://mywiki.wooledge.org/ParsingLs) parse the output of ls. – sorpigal Nov 30 '10 at 19:13
  • 1
    possible duplicate of [Bash: check if an array contains a value](http://stackoverflow.com/questions/3685970/bash-check-if-an-array-contains-a-value) – Gilles 'SO- stop being evil' Nov 30 '10 at 20:08
  • 1
    Note that the line `array=$( ls )` doesn't involve any array. It sets the *string* variable called `array` to something that resembles the list of files in the current directory separated by newlines, except that nonprintable characters may be mangled. If you want to have an array variable whose elements are the names of the files in the current directory (except those whose name begins with a dot), `a=(*)` will do it. – Gilles 'SO- stop being evil' Nov 30 '10 at 20:11
  • @Gilles: I'd say it's slightly different. The question specified "a list of files" and not an array. Finding one file out of a list is not necessarily the same thing. It just so happens that loading the list into an array is a probable part of the answer. – sorpigal Nov 30 '10 at 21:08

3 Answers3

3
if ls | grep -q -x t1 ; then
  echo Success
else
  echo Failure                                                                                
fi

grep -x matches full lines only, so ls | grep -x only returns something if the file exists.

moinudin
  • 117,949
  • 42
  • 185
  • 213
  • 2
    Better to say `if ls | grep -q -x log.out ; then ... `, no need for the extra subsehell. Of course using ls this way is also a very bad idea. – sorpigal Nov 30 '10 at 19:26
  • @Sorpigal Edited, and yes I agree with your comment about parsing ls (I upvoted it). – moinudin Nov 30 '10 at 19:28
  • 1
    ¿Any reason why using ls this way is a bad idea? – kjetil b halvorsen Nov 30 '10 at 22:59
  • 1
    Quoting from [BashPitfalls](http://mywiki.wooledge.org/BashPitfalls#for_i_in_.24.28ls_.2A.mp3.29): _Never try to parse the output of ls. ls is just plain unnecessary. It's an external command whose output is intended specifically to be read by a human, not parsed by a script_. I think that pretty well characterizes why globs or `find` are preferred. – TheDudeAbides Nov 10 '17 at 21:36
2

How about

in_list() {
    local search="$1"
    shift
    local list=("$@")
    for file in "${list[@]}" ; do
        [[ $file == $search ]] && return 0
    done
    return 1
}

if in_list log.out * ; then
    echo 'success!'
else
    echo 'bad!'
fi

EDIT: made it a bit less idiotic.

EDIT #2: Of course if all you're doing is looking in the current directory to see if a particular file is there, which is effectively what the above is doing, then you can just say

[ -e log.out ] && echo 'success!' || echo 'bad!'

If you're actually doing something more complicated involving lists of files then this might not be sufficient.

sorpigal
  • 23,262
  • 7
  • 54
  • 73
  • You would probably want to use quotes in your test: `[[ "$file" == "$search" ]]` – glenn jackman Nov 30 '10 at 20:56
  • 2
    @glenn: Quotes are unnecessary [inside double square brackets](http://stackoverflow.com/questions/3869072/test-for-non-zero-length-string-in-bash-n-var-or-var/3870055#3870055). – Dennis Williamson Nov 30 '10 at 21:01
  • 1
    And edited back. I'd support always quoting variable expansions even when not necessary, just to make it a habit, but for sample purposes simple is probably better. – sorpigal Nov 30 '10 at 21:06
2

If you just want to check if a file exists, then

[[ -f "$file" ]] && echo yes || echo no

If your array contains a list of files generated by some means other than ls, then you have to iterate over it as demonstrated by Sorpigal.

glenn jackman
  • 207,528
  • 33
  • 187
  • 305
  • I feel like this is the most correct answer. If the OP needed something more specific than just `*`, then something like `for file in ./*.ext; do test -f "$file" || echo "no"; done` seems to be the [preferred way](http://mywiki.wooledge.org/BashPitfalls#for_i_in_.24.28ls_.2A.mp3.29) to do it. No need for `ls` at all, and certainly no need for `grep`. – TheDudeAbides Nov 10 '17 at 21:38