Check if file exists [BASH]

2019-06-13 16:08发布

问题:

How do I check if file exists in bash?

When I try to do it like this:

FILE1="${@:$OPTIND:1}"
if [ ! -e "$FILE1" ]
then 
    echo "requested file doesn't exist" >&2
    exit 1
elif
<more code follows>

I always get following output:

 requested file doesn't exist

The program is used like this:

script.sh [-g] [-p] [-r FUNCTION_ID|-d FUNCTION_ID] FILE

Any ideas please? I will be glad for any help.

P.S. I wish I could show the entire file without the risk of being fired from school for having a duplicate. If there is a private method of communication I will happily oblige.

My mistake. Fas forcing a binary file into a wrong place. Thanks for everyone's help.

回答1:

To (recap) and add to @DavidW.'s excellent answer:

  • Check the shebang line (first line) of your script to ensure that it's executed by bash: is it #!/bin/bash or #!/usr/bin/env bash?

  • Inspect your script file for hidden control characters (such as \r) that can result in unexpected behavior; run cat -v scriptFile | fgrep ^ - it should produce NO output; if the file does contain \r chars., they would show as ^M.

    • To remove the \r instances (more accurately, to convert Windows-style \r\n newline sequences to Unix \n-only sequences), you can use dos2unix file to convert in place; if you don't have this utility, you can use sed 's/'$'\r''$//' file > outfile (CAVEAT: use a DIFFERENT output file, otherwise you'll destroy your input file); to remove all \r instances (even if not followed by \n), use tr -d '\r' < file > outfile (CAVEAT: use a DIFFERENT output file, otherwise you'll destroy your input file).
  • In addition to @DavidW.'s great debugging technique, you can add the following to visually inspect all arguments passed to your script:
i=0; for a; do echo "\$$((i+=1))=[$a]"; done 

(The purpose of enclosing the value in [...] (for example), is to see the exact boundaries of the values.)

This will yield something like:

$1=[-g]
$2=[input.txt]
...

Note, though, that nothing at all is printed if no arguments were passed.



回答2:

Little trick to debugging problems like this. Add these lines to the top of your script:

export PS4="\$LINENO: "
set -xv

The set -xv will print out each line before it is executed, and then the line once the shell interpolates variables, etc. The $PS4 is the prompt used by set -xv. This will print the line number of the shell script as it executes. You'll be able to follow what is going on and where you may have problems.

Here's an example of a test script:

#! /bin/bash

export PS4="\$LINENO: "
set -xv

FILE1="${@:$OPTIND:1}"         # Line 6
if [ ! -e "$FILE1" ]           # Line 7
then 
    echo "requested file doesn't exist" >&2
    exit 1
else
    echo "Found File $FILE1"   # Line 12
fi

And here's what I get when I run it:

$ ./test.sh .profile
    FILE1="${@:$OPTIND:1}"
6: FILE1=.profile
    if [ ! -e "$FILE1" ]
    then 
        echo "requested file doesn't exist" >&2
        exit 1
    else
        echo "Found File $FILE1"
    fi
7: [ ! -e .profile ]
12: echo 'Found File .profile'
Found File .profile

Here, I can see that I set $FILE1 to .profile, and that my script understood that ${@:$OPTIND:1}. The best thing about this is that it works on all shells down to the original Bourne shell. That means if you aren't running Bash as you think you might be, you'll see where your script is failing, and maybe fix the issue.

I suspect you might not be running your script in Bash. Did you put #! /bin/bash on the top?


script.sh [-g] [-p] [-r FUNCTION_ID|-d FUNCTION_ID] FILE

You may want to use getopts to parse your parameters:

#! /bin/bash

USAGE=" Usage:
    script.sh [-g] [-p] [-r FUNCTION_ID|-d FUNCTION_ID] FILE
"
while getopts gpr:d: option
do
    case $option in
        g)  g_opt=1;;
        p)  p_opt=1;;
        r)  rfunction_id="$OPTARG";;
        d)  dfunction_id="$OPTARG";;
        [?])
            echo "Invalid Usage" 1>&2
            echo "$USAGE"        1>&2
            exit 2
            ;;
    esac
done

if [[ -n $rfunction_id && -n $dfunction_id ]]
then
    echo "Invalid Usage: You can't specify both -r and -d" 1>&2
    echo "$USAGE" >2&
    exit 2
fi

shift $(($OPTIND - 1))
[[ -n $g_opt ]] && echo "-g was set"
[[ -n $p_opt ]] && echo "-p was set"
[[ -n $rfunction_id ]] && echo "-r was set to $rfunction_id"
[[ -n $dfunction_id ]] && echo "-d was set to $dfunction_id"
[[ -n $1 ]] && echo "File is $1"


回答3:

Try to print FILE1 to see if it has the value you want, if it is not the problem, here is a simple script (site below):

#!/bin/bash
file="${@:$OPTIND:1}"
if [ -f "$file" ]
then
    echo "$file found."
else
    echo "$file not found."
fi

http://www.cyberciti.biz/faq/unix-linux-test-existence-of-file-in-bash/



回答4:

Instead of plucking an item out of "$@" in a tricky way, why don't you shift off the args you've processed with getopts:

while getopts ...
done

shift $(( OPTIND - 1 ))

FILE1=$1


标签: bash shell