variable - bash意思




如何判斷Bash中是否存在常規文件? (12)

我使用以下腳本來查看文件是否存在:

#!/bin/bash

FILE=$1     
if [ -f $FILE ]; then
   echo "File $FILE exists."
else
   echo "File $FILE does not exist."
fi

如果我只想檢查文件是否存在,使用的語法是什麼?

#!/bin/bash

FILE=$1     
if [ $FILE does not exist ]; then
   echo "File $FILE does not exist."
fi

test命令( [這裡]有一個“not”邏輯運算符,它是感嘆號(類似於許多其他語言)。 試試這個:

if [ ! -f /tmp/foo.txt ]; then
    echo "File not found!"
fi


你可以用“!”來否定表達式:

#!/bin/bash
FILE=$1

if [ ! -f "$FILE" ]
then
    echo "File $FILE does not exist"
fi

相關的手冊頁是man test或者等同於man [ - 或help testhelp [用於內置bash命令。


你可以這樣做:

[[ ! -f "$FILE" ]] && echo "File doesn't exist"

要么

if [[ ! -f "$FILE" ]]; then
    echo "File doesn't exist"
fi

如果要同時檢查文件和文件夾,請使用-e選項而不是-f-e對常規文件,目錄,套接字,字符特殊文件,塊特殊文件等返回true。


[ -f "$file" ]

[命令對存儲在$file的路徑執行stat() (不是lstat() )系統調用,如果系統調用成功,則返回truestat()返回的文件類型為“regular”。

因此,如果[ -f "$file" ]返回true,您可以告訴該文件確實存在,並且是一個常規文件或符號鏈接最終解析為常規文件(或者至少是在stat() )。

但是,如果它返回false (或者如果[ ! -f "$file" ]! [ -f "$file" ]返回true),則有許多不同的可能性:

  • 該文件不存在
  • 該文件存在但不是常規文件
  • 該文件存在,但您沒有父目錄的搜索權限
  • 該文件存在,但訪問它的路徑太長
  • 該文件是常規文件的符號鏈接,但您沒有對符號鏈接解析中涉及的某些目錄的搜索權限。
  • ... stat()系統調用可能失敗的任何其他原因。

簡而言之,它應該是:

if [ -f "$file" ]; then
  printf '"%s" is a path to a regular file or symlink to regular file\n' "$file"
elif [ -e "$file" ]; then
  printf '"%s" exists but is not a regular file\n' "$file"
elif [ -L "$file" ]; then
  printf '"%s" exists, is a symlink but I cannot tell if it eventually resolves to an actual file, regular or not\n' "$file"
else
  printf 'I cannot tell if "%s" exists, let alone whether it is a regular file or not\n' "$file"
fi

要確定該文件不存在,我們需要使用stat()系統調用返回錯誤代碼ENOENTENOTDIR告訴我們其中一個路徑組件不是目錄是我們可以告訴的另一種情況該路徑不存在該文件)。 不幸的是[命令不讓我們知道。 無論錯誤代碼是ENOENT,EACCESS(權限被拒絕),ENAMETOOLONG還是其他任何內容,它都將返回false。

[ -e "$file" ]測試也可以使用ls -Ld -- "$file" > /dev/null 。 在這種情況下, ls將告訴您stat()失敗的原因,儘管信息不能以編程方式輕鬆使用:

$ file=/var/spool/cron/crontabs/root
$ if [ ! -e "$file" ]; then echo does not exist; fi
does not exist
$ if ! ls -Ld -- "$file" > /dev/null; then echo stat failed; fi
ls: cannot access '/var/spool/cron/crontabs/root': Permission denied
stat failed

至少ls告訴我這不是因為文件不存在而失敗了。 這是因為它無法判斷文件是否存在。 [命令只是忽略了問題。

使用zsh shell,您可以在失敗的[ command]之後使用$ERRNO特殊變量查詢錯誤代碼,並使用zsh/system模塊中的$errnos special數組解碼該數字:

zmodload zsh/system
ERRNO=0
if [ ! -f "$file" ]; then
  err=$ERRNO
  case $errnos[err] in
    ("") echo exists, not a regular file;;
    (ENOENT|ENOTDIR)
       if [ -L "$file" ]; then
         echo broken link
       else
         echo does not exist
       fi;;
    (*) echo "can't tell"; syserror "$err"
  esac
fi

(注意當使用最新版本的gcc構建時,某些版本的zsh會損壞$errnos支持 )。


您應該小心為不帶引號的變量運行test ,因為它可能會產生意外的結果:

$ [ -f ]
$ echo $?
0
$ [ -f "" ]
$ echo $?
1

建議通常是讓測試變量用雙引號括起來:

#!/bin/sh
FILE=$1

if [ ! -f "$FILE" ]
then
   echo "File $FILE does not exist."
fi

最簡單的方法

FILE=$1
[ ! -e "${FILE}" ] && echo "does not exist" || echo "exists"

有三種不同的方法可以做到這一點:

  1. 用bash否定退出狀態(沒有其他答案說過這個):

    if ! [ -e "$file" ]; then
        echo "file does not exist"
    fi
    

    要么:

    ! [ -e "$file" ] && echo "file does not exist"
    
  2. 否定測試命令中的測試[ (這是之前大多數答案的方式):

    if [ ! -e "$file" ]; then
        echo "file does not exist"
    fi
    

    要么:

    [ ! -e "$file" ] && echo "file does not exist"
    
  3. 根據測試結果為負( ||而不是&& ):

    只要:

    [ -e "$file" ] || echo "file does not exist"
    

    這看起來很愚蠢(IMO),除非您的代碼必須可移植到Bourne shell(如Solaris 10或更早版本的/bin/sh ),而且缺少管道否定運算符( ! ),否則不要使用它:

    if [ -e "$file" ]; then
        :
    else
        echo "file does not exist"
    fi
    

此shell腳本也適用於在目錄中查找文件:

echo "enter file"

read -r a

if [ -s /home/trainee02/"$a" ]
then
    echo "yes. file is there."
else
    echo "sorry. file is not there."
fi

要反轉測試,請使用“!”。 這相當於其他語言中的“非”邏輯運算符。 試試這個:

if [ ! -f /tmp/foo.txt ];
then
    echo "File not found!"
fi

或以稍微不同的方式書寫:

if [ ! -f /tmp/foo.txt ]
    then echo "File not found!"
fi

或者您可以使用:

if ! [ -f /tmp/foo.txt ]
    then echo "File not found!"
fi

或者,將所有人放在一起:

if ! [ -f /tmp/foo.txt ]; then echo "File not found!"; fi

可以寫入(使用“和”運算符:&&)作為:

[ ! -f /tmp/foo.txt ] && echo "File not found!"

看起來像這樣短:

[ -f /tmp/foo.txt ] || echo "File not found!"

這段代碼也有效。

#!/bin/bash
FILE=$1
if [ -f $FILE ]; then
 echo "File '$FILE' Exists"
else
 echo "The File '$FILE' Does Not Exist"
fi

[[ -f $FILE ]] || printf '%s does not exist!\n' "$FILE"

此外,文件可能是破壞的符號鏈接,或非常規文件,例如套接字,設備或fifo。 例如,要添加對損壞的符號鏈接的檢查:

if [[ ! -f $FILE ]]; then
    if [[ -L $FILE ]]; then
        printf '%s is a broken symlink!\n' "$FILE"
    else
        printf '%s does not exist!\n' "$FILE"
    fi
fi




scripting