通常のファイルがBashに存在しないかどうかを確認するにはどうすればよいですか?


3264

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

#!/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


9
私は非常に怠惰な人間なので、通常、次のばかげた回避策の構成を使用します。if [ -f $FILE ]; then; else; echo "File $FILE does not exist."; fi;この質問を代わりに見つけて、より適切な方法でそれを学んだことはおそらく良いことです。:)
Alderath、2013年

5
ほとんどのUNIX / POSIXドキュメントは一般にすべてのタイプのファイルシステムエントリを単に「ファイル」と呼んでいるため、「通常のファイル」と言う必要があります。たとえば、シンボリックリンクは名前付きパイプと同様に、ファイルのタイプです。 、通常のファイル、ディレクトリ、ブロックスペシャル、キャラクタースペシャル、ソケットなど
kevinarpe 2013年

11
@kevinarpe 何かが存在するかどうかをテストする場合は、を使用します-e。-fは、などのディレクトリ、シンボリックリンクを、ピックアップしていないだろう
Benubird

14
安全のため、常に二重引用符を使用して、空白を含むファイル名を正しく処理してください。例:FILE=$1-> FILE="$1"およびif [ -f $FILE ];->if [ -f "$FILE" ];
kevinarpe

回答:


4524

テストコマンド([ここでは)(他の多くの言語と同様)感嘆符で「ない」論理演算子を持っています。これを試して:

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

208
より簡潔に:[!-f /tmp/foo.txt] && echo「ファイルが見つかりません!」
DavidWinterbottom 2010

38
「2つのファイルのいずれかが存在しない場合」の正しい構文を見つけるのに少し苦労しました。次の仕事の両方:if [ ! \( -f "f1" -a -f "f2" \) ] ; then echo MISSING; fi if [ ! -f "f1" ] || [ ! -f "f2" ] ; then echo MISSING; fi
mivk

153
@DavidWinterbottomさらにジューシーに:[ -f /tmp/foo.txt ] || echo "File not found!"
David W.

27
:パラメータは、次のいずれかになります-e: Returns true value, if file exists -f: Return true value, if file exists and regular file -r: Return true value, if file exists and is readable -w: Return true value, if file exists and is writable -x: Return true value, if file exists and is executable -d: Return true value, if exists and is a directory
SD。

5
! -fwithの&&使用-fとwithの使用には非対称性があり||ます。これは、存在しないことの確認によって返される終了コードに関係しています。行が常に終了コード0で正常に終了する必要がある場合(およびこの制約が不要な場合があります)、2つのアプローチは交換可能ではありません。または、ifステートメントを使用するだけで、非存在チェックの終了コードを気にする必要がなくなります。
Acumenus 2015

670

Bashファイルのテスト

-b filename-ブロック特殊ファイル
-c filename-特殊文字ファイル
-d directoryname-ディレクトリの存在の
-e filename確認-タイプ(ノード、ディレクトリ、ソケットなど)に関係なく、ファイルの存在を確認します- ディレクトリではなく
-f filename通常のファイルの存在を確認します
-G filename-ファイルが存在し、所有されているかどうかを確認します有効なグループID-
-G filename set-group-idファイルが存在し、セットグループIDの場合はTrue-
-k filenameスティッキービット
-L filename-シンボリックリンク
-O filename-ファイルが存在し、有効なユーザーIDが所有する場合はTrue-
-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 

1
@ 0x90必要に応じて、私の投稿を自由に編集してリストに追加できます。私はあなたが意味していると思います:-n String-文字列の長さがゼロでないかどうか確認してください。あるいはfile1 -nt file2、file1がfile 2よりも新しいかどうかを確認します(それより古い場合は-otを使用することもできます)
BlueCacti

1
:-nについて The unary operator -z tests for a null string, while -n or no operator at all returns True if a string is not empty.ibm.com/developerworks/library/l-bash-test/index.html
BlueCacti

1
なぜいくつかはfunction exists()のような関数を追加しなかったのですか{⏎if [-e "$ 1"]; 次に、「$ 1が存在する」とエコーします。それ以外の場合は、「$ 1が存在しない」とエコーします。fi}
Mz A

291

「!」で式を否定できます:

#!/bin/bash
FILE=$1

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

関連するmanページは、man testまたは同等のman [-またはhelp testor help [で、組み込みのbashコマンドです。


4
ではbashの[組み込みです。したがって、関連情報はむしろhelp [... によって取得されますが、これは組み込みの[同義語であることを示しているtestため、関連情報はむしろによって取得されhelp testます。マニュアルのBash条件式」セクションも参照してください。
gniourf_gniourf 2013年

@gniourf_gniourf:はい。ただし、bash組み込み[コマンドは外部[コマンドと非常に似た動作をするので、man testまたはのどちらかで、それman [がどのように機能するかをよく理解できます。
キース・トンプソン

8
ことを除いて@KeithThompson 、bashの組み込みは、[外部コマンドがより多くのスイッチがある[一般的に私はそれがドキュメントの特定のツールに固有ではなく、別の漠然と関連のものに文書の特定を読む方が良いでしょうと信じて話す...私のシステム上で見つかりました。しかし、私は間違っているかもしれません;)
gniourf_gniourf 2013

134
[[ -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

9
テストで2つの「[」を使用する理由を尋ねてもよいですか。(例[[!-a $ FILE]])。私はソラリスボックスで言及されたすべてのオプションを試してみましたが、それだけがうまくいったので感謝していますが、なぜですか?
Dimitrios Mistriotis 2011

30
二重括弧は「モダン」な拡張です。たとえば、単語の分割は行われず(スペースを含むファイル名など)、空の文字列でも機能します:mywiki.wooledge.org/BashFAQ/031
bw1024

7
tldp.org/LDP/abs/html/fto.htmlによれば、-aは実質的に-eと同じです。「非推奨」であり、その使用は推奨されません。とにかく、壊れたシンボリックリンクをチェックすることについて言及したことに対して+1
Luca Borrione

4
@dimitrismistriotis two "["は、zshとbashによって(異なる方法で)実装された移植性のない拡張です。一般的には、可能であればそれを避けるべきです。
良い人

7
[[。広く使用されている拡張機能です。bashを使用していることがわかっている場合は、bashを使用しない理由はありません。[よりエラーが発生しにくいです。
マイケル・ポッター

101

単一のコマンドを実行する必要がある場合は、省略できることに言及する価値があります

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

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

または

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

ありがとう![[]]を使用しない代替案が必要
Jonathan

69

私は、POSIXシェル互換形式で、次の1行を実行することを好みます。

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

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

スクリプトで行うようないくつかのコマンドの場合:

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

これを始めたら、完全に型付けされた構文を使用することはめったにありません!!


1
まず、引用符で囲まれていない変数参照はエラーが発生しやすくなります。とは言っても、 bashのマンページで、[またはtest組み込みが(とは対照的に)デフォルトで引数のファイルの存在をテストすること-eどこにありますか?あいまいではないでしょうか?AFAIK(およびAIUIセクション「条件式」セクション)でテストした唯一のことは、引数が空ではない(または未定義である)ことです。つまり、この場合、トートロジー(let $DIR = ''および)$FILE = ''であり、引数はまだ'//')。
PointedEars

1
証明:ls /foo、結果ls: cannot access /foo: No such file or directory[ /foo ] && echo 42、結果42。GNU bash、バージョン4.2.37(1)-release(i486-pc-linux-gnu)。
PointedEars

@PointedEars:-fこの回答を書いた時点で、オプションの指定に失敗しました。明らかに-eそれが通常のファイルになるかどうかわからない場合は、いつでもを使用できます。さらに、すべてのスクリプトでこれらの構成要素を引用していますが、適切な証明なしにこれを送信したに違いありません。
JMベッカー

ACK。しかし、おそらくワンライナーでif-else問題を解決できないことはご存じでしょう[ $condition ] && if_true || if_false。エラーが発生しやすいのです。いずれにしても、私[ ! -f "$file" ] && if_not_existsよりも読みやすく、理解しやすいと思います[ -f "$file" ] || if_not_exists
PointedEars

55

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

-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

39

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

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

または

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

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


1
これはbash固有ではありません。構文はKornシェルからのものであり、zshおよびbashでも使用できます。[ただし、ここでは標準ユーティリティよりも利点が限られています。
ステファンChazelas

通常のファイル(によってチェックされる-f)とディレクトリは、さまざまなタイプのファイルの 2つにすぎません。ソケット、シンボリックリンク、デバイス、fifo、ドアなどもあり[ -eます。シンボリックリンクの解決後に、ファイルの存在(通常、fifo、ディレクトリなど、あらゆるタイプのもの)がテストされます。
ステファンChazelas 2018年

@StephaneChazelas:kshまたはzshタグがどこにも表示されません。私たちはbashや、ほとんどのUNIXシステムで標準化されているものについて話しています。したがって、コンテキスト内では、bash固有です。OPはそこにあるすべてのシェルを知る必要はありません:D
Jahid

これは、回答の「Bash固有」の部分に対するコメントでした。
Stephane Chazelas

@StephaneChazelas:はい、そしてコンテキスト(bashおよび標準sh)内では、bash固有です。2番目のコメントには要点がありません。完全に文脈外です。OPは必要ありません-e、彼は必要-fです。
Jahid

35

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

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

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

#!/bin/sh
FILE=$1

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

8
不必要なまれなケース、または有害なまれなケースのいずれかがあることを正確に知らない限り、すべての変数を二重引用符で囲むことをお勧めします。(いいえ、これはそれらの1つではありません。)
Uwe

なぜ二重引用符を使用しないのか、詳しく説明していただけませんか?それ以外の場合、コメントに有用性がありません。
artdanil 2013年

4
つまり、これが不要または有害なまれなケースではありません。シェルプログラマーは、(ほとんど)すべての変数を二重引用符で囲む必要があります。このルールはに限定されません[ ... ]
Uwe 2013年


24

これを行うには、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シェル(Solaris 10以前など)にコードを移植する必要がある場合を除き、使用しないでください。

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

との移植性の違いは! [あり[ !ますか?
Frozen Flame

3
! [ シェルのパイプライン2.9.2(任意のコマンド)のためのPOSIXある Otherwise, the exit status shall be the logical NOT of the exit status of the last command[ ! テストのためのPOSIXある ! expression True if expression is false. False if expression is true.ので、両方のPOSIX、そして私の経験であり、両方の広範囲にサポートされています。

1
@ FrozenFlame、Bourneシェルには!、Kornシェルによって導入されたキーワードがありませんでした。Solaris 10以前を除いて、最近ではボーンシェルに出くわすことはほとんどありません。
ステファンChazelas 2018年

22

[ -f "$file" ]

[コマンドがないstat()(ないlstat()に保存されているパス上の)システムコールを$fileして返すそのシステムコールが成功し、で返されるファイルの種類があればstat()、「ある正規の」。

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

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

  • ファイルは存在しません
  • ファイルは存在しますが、通常のファイルではありません(デバイス、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

ファイルが存在しないことを確認するにはstat()、エラーコードENOENTENOTDIRがパスコンポーネントの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

(の最新バージョンでビルドした場合$errnos、一部のバージョンでzshgccサポートが壊れていました)。


11

テストを元に戻すには、「!」を使用します。これは、他の言語の「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

これは次のように記述できます( "and"演算子:&&を使用):

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

これは次のように短く見えます:

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


10

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

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


6

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

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

3
これが、他の答えがまだ与えていない何かを追加するかどうかは明らかではありません。パス名をハードコーディングします。質問にはbashのタグが付いているので、read -p "Enter file name: " -r a読むだけでなくプロンプトを表示するためにも使用できます。変数を引用符で囲みます。それは良いことですが、説明する必要があります。ファイル名をエコーし​​た方が良いかもしれません。そして、これはファイルが存在し、空ではないこと(つまりの意味-s)をチェックしますが、質問は空かどうか(-fより適切なファイル)について質問します。
ジョナサンレフラー、2015

4

&&と||を使用すると便利な場合があります。演算子。

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

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

または

test -b $FILE || echo File there!

2

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

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

0

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

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

または

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

ファイル名が存在しない場合、出力は次のようになります

test1
test2
test3

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


1
いいえ、中括弧表記はない bashの専用。POSIX準拠のシェルで動作します。
Charles Duffy

0
envfile=.env

if [ ! -f "$envfile" ]
then
    echo "$envfile does not exist"
    exit 1
fi

コードとともに説明を入力してください。
zohar

このコードはOPの問題を解決する可能性がありますが、コードがOPの問題にどのように対処するかについての説明を含めることをお勧めします。このようにして、将来の訪問者はあなたの投稿から学び、それを自分のコードに適用できます。SOはコーディングサービスではなく、知識のリソースです。また、質の高い、完全な回答が支持される可能性が高くなります。これらの機能は、すべての投稿が自己完結型であるという要件とともに、フォーラムとは異なるプラットフォームとしてのSOの強みの一部です。編集して追加情報を追加したり、ソースドキュメントで説明を補足したりできます。
ysf
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.