web-dev-qa-db-ja.com

通常のファイルがBashに存在しない場合、どうすればわかりますか?

ファイルが存在するかどうかを確認するために、次のスクリプトを使用しました。

#!/bin/bash

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

ファイルが not が存在するかどうかだけを確認したい場合に使用する正しい構文は何ですか?

#!/bin/bash

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

test コマンド(ここでは[)は感嘆符(他の多くの言語と同様)である "not"論理演算子を持ちます。これを試して:

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

Bashファイルのテスト

-b filename - ブロックスペシャルファイル
-c filename - 特殊文字ファイル
-d directoryname - ディレクトリの存在を確認する
-e filename - 種類(ノード、ディレクトリ、ソケットなど)に関係なく、ファイルの存在を確認します
-f filename - ディレクトリではなく通常のファイルの存在をチェックする
-G filename - ファイルが存在し、実効グループIDによって所有されているかどうかを確認します
-G filename set-group-id - ファイルが存在し、set-group-idであれば真
-k filename - スティッキービット
-L filename - シンボリックリンク
-O filename - ファイルが存在し、実効ユーザーIDによって所有されている場合は真
-r filename - ファイルが読み込み可能か確認する
-S filename - ファイルがソケットかどうかを調べる
-s filename - ファイルがゼロ以外のサイズかどうかを調べる
-u filename - ファイルのset-user-idビットが設定されているか確認する
-w filename - ファイルが書き込み可能かどうかを調べる
-x filename - ファイルが実行可能かどうかを調べる

使い方:

#!/bin/bash
file=./file
if [ -e "$file" ]; then
    echo "File exists"
else 
    echo "File does not exist"
fi 

テスト式 は、!演算子を使用して否定できます。

#!/bin/bash
file=./file
if [ ! -e "$file" ]; then
    echo "File does not exist"
else 
    echo "File exists"
fi 
570
BlueCacti

"!"で式を否定することができます。

#!/bin/bash
FILE=$1

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

関連するmanページは、組み込みのbashコマンドの場合はman testman [ - 、help testhelp [です。

271
unbeknown
[[ -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
124
guns

単一のコマンドを実行する必要がある場合は、省略することができます。

if [ ! -f "$file" ]; then
    echo "$file"
fi

test -f "$file" || echo "$file"

または

[ -f "$file" ] || echo "$file"
88

_ posix _ Shell互換形式で、次のようなワンライナーを実行するのが好きです。

$ [ -f "/$DIR/$FILE" ] || echo "$FILE NOT FOUND"

$ [ -f "/$DIR/$FILE" ] && echo "$FILE FOUND"

私がスクリプトでするように、いくつかのコマンドのために:

$  [ -f "/$DIR/$FILE" ] || { echo "$FILE NOT FOUND" ; exit 1 ;}

私がこれをし始めたら、私はもう完全に型指定された構文をもう使うことはありません!

63
J. M. Becker

ファイルの存在をテストするために、パラメータは次のいずれかになります。

-e: Returns true if file exists (regular file, directory, or symlink)
-f: Returns true if file exists and is a regular file
-d: Returns true if file exists and is a directory
-h: Returns true if file exists and is a symlink

以下のテストはすべて通常のファイル、ディレクトリ、シンボリックリンクに適用されます。

-r: Returns true if file exists and is readable
-w: Returns true if file exists and is writable
-x: Returns true if file exists and is executable
-s: Returns true if file exists and has a size > 0

スクリプト例:

#!/bin/bash
FILE=$1

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

あなたはこれを行うことができます:

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

または

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

ファイルとフォルダの両方を確認したい場合は、-eではなく-fオプションを使用してください。 -eは、通常のファイル、ディレクトリ、ソケット、キャラクタ型スペシャルファイル、ブロック型スペシャルファイルなどに対してtrueを返します。

33
Jahid

引用符で囲まれていない変数に対してtestを実行すると、予期しない結果が生じる可能性があるため、注意が必要です。

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

通常は、テスト対象の変数を二重引用符で囲むことをお勧めします。

#!/bin/sh
FILE=$1

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

これを行うには、3つの異なる方法があります。

  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)、パイプライン否定演算子(/bin/sh)を欠いたBourne Shell(Solaris 10以前の!など)にコードを移植する必要がない限り、使用しないでください:

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

[ -f "$file" ]

[コマンドは、$fileに格納されているパスに対してstat()lstat()ではなく)システムコールを実行し、そのシステムコールが成功し、stat()によって返されるファイルのタイプが "regular"の場合はtrueを返します。

[ -f "$file" ]がtrueを返す場合、ファイルが存在し、通常のファイルまたは最終的に通常のファイルに解決されるシンボリックリンクであることがわかります(少なくともstat()の時点ではそうなっていました)。

ただし、falseが返された場合(または[ ! -f "$file" ]または! [ -f "$file" ]がtrueを返した場合)、さまざまな可能性があります。

  • ファイルが存在しません
  • ファイルは存在するがregularファイルではない(デバイス、fifo、ディレクトリ、ソケットなど)
  • ファイルは存在しますが、親ディレクトリに対する検索権限がありません
  • ファイルは存在しますが、アクセスするためのパスが長すぎます
  • ファイルは通常のファイルへのシンボリックリンクですが、シンボリックリンクの解決に関連するディレクトリの中には検索権限がないものもあります。
  • ... 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

ファイルが存在しないことを確実に知るためには、エラーコードENOENTを返して返すstat()システムコールが必要です。(ENOTDIRは、パスコンポーネントの1つがディレクトリではないことを示しています。そのパスには存在しません。残念ながら、[コマンドではそれがわかりません。エラーコードが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シェルを使用すると、失敗した$ERRNOコマンドの後に[特殊変数を使用してエラーコードを照会し、$errnosモジュールのzsh/system特殊配列を使用してその番号をデコードできます。

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;;
    (*) syserror -p "can't tell: " "$err"
  esac
fi

zshの最近のバージョンでビルドされた場合、gccの一部のバージョンでは$errnosサポートが壊れていました )。

19

テストを元に戻すには、 "!"を使用します。これは、他の言語の "not"論理演算子と同じです。これを試して:

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

これは(then and演算子:&&を使って)次のように書くことができます。

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

これは以下のように短く見えます。

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

このコードも機能します。

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

testも重要です。それは私のために働きました(Bash Shell:Check File Exists or Notに基づく):

test -e FILENAME && echo "File exists" || echo "File doesn't exist"
8

最も簡単な方法

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

このシェルスクリプトは、ディレクトリ内のファイルを見つけるためにも機能します。

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
5
Simmant

&&と||を使うと便利なことがあります。演算子。

(コマンド "test"がある場合)のように:

test -b $FILE && echo File not there!

または

test -b $FILE || echo File there!
3
André

[]の代わりにtestを使用する場合は、!を使用して否定を取得できます。

if ! test "$FILE"; then
  echo "does not exist"
fi
0
Mauro Zallocco

1つのライナーに複数のコマンドをグループ化することもできます

[ -f "filename" ] || ( echo test1 && echo test2 && echo test3 )

または

[ -f "filename" ] || { echo test1 && echo test2 && echo test3 ;}

Filenameが終了しない場合、出力は

test1
test2
test3

注:(...)はサブシェルで実行され、{...;}は同じシェルで実行されます。中括弧表記はbashでのみ機能します。

0
upteryx