Linux Bash スクリプトにファイルが存在するかどうかを確認する方法

公開: 2022-08-18
bash プロンプトを表示している Linux ラップトップ
Fatmawati achmad zaenuri/Shutterstock.com

Linux Bash スクリプトが、存在する特定のファイルまたはディレクトリに依存している場合、それらが存在すると仮定することはできません。 それらが確実に存在することを確認する必要があります。 その方法は次のとおりです。

何も仮定しないでください

スクリプトを書いているとき、コンピュータ上に存在するものと存在しないものについて推測することはできません。 スクリプトが配布され、多くの異なるコンピューターで実行される場合、これは二重に当てはまります。 遅かれ早かれ、スクリプトは想定を満たさないコンピューターで実行され、スクリプトは失敗するか、予期せず実行されます。

私たちがコンピュータ上で大切にしたり作成したりするものはすべて、何らかの形式のファイルに保存され、それらのファイルはすべてディレクトリに存在します。 スクリプトは、ファイルやディレクトリの読み取り、書き込み、名前の変更、削除、移動など、コマンド ラインで実行できるすべての操作を実行できます。

人間としての利点は、ディレクトリの内容を確認でき、ファイルが存在するかどうか、または予想されるディレクトリが存在するかどうかを知ることができることです。 スクリプトがファイルを操作しているときに問題が発生すると、深刻で有害な結果が生じる可能性があります。

Bash には、ファイルとディレクトリを検出し、それらの属性の多くをテストするために使用できる包括的なテスト セットが用意されています。 これらをスクリプトに組み込むのは簡単ですが、堅牢性と細かい制御の点で大きなメリットがあります。

関連: Linux で二重括弧条件付きテストを使用する方法

テストの範囲

if ステートメントを、多数のファイルおよびディレクトリ テストからの適切なテストと組み合わせることで、ファイルが存在するかどうか、実行可能か書き込み可能かなどを簡単に判断できます。

  • -b : ファイルがブロック スペシャル ファイルの場合は true を返します。
  • -c : ファイルがキャラクタ スペシャルの場合は true を返します。
  • -d : 「ファイル」がディレクトリの場合、true を返します。
  • -e : ファイルが存在する場合は true を返します。
  • -f : ファイルが存在し、通常のファイルである場合に true を返します。
  • -g : ファイルにsetgidパーミッション セット ( chmod g+ ) がある場合に true を返します。
  • -h : ファイルがシンボリック リンクの場合は true を返します。
  • -L : ファイルがシンボリック リンクの場合は true を返します。
  • -k : スティッキー ビットが設定されている場合 ( chmod +t )、true を返します。
  • -p : ファイルが名前付きパイプの場合は true を返します。
  • -r : ファイルが読み取り可能であれば true を返します。
  • -s : ファイルが存在し、空でない場合は true を返します。
  • -S : ファイルがソケットの場合は true を返します。
  • -t : ファイル記述子が端末で開かれている場合は true を返します。
  • -u : ファイルにsetuidパーミッション セット ( chmod u+ ) がある場合に true を返します。
  • -w : ファイルが書き込み可能な場合は true を返します。
  • -x : ファイルが実行可能であれば true を返します。
  • -O : が所有されている場合は true を返します。
  • -G : がグループによって所有されている場合は true を返します。
  • -N : ファイルが最後に読み取られてから変更されている場合は true を返します。
  • ! : 論理否定演算子。
  • && : 論理 AND 演算子。
  • || : 論理 OR 演算子。

-aテストは廃止され、 -eテストに置き換えられたため、リストは-bで始まります。

関連: Linux で SUID、SGID、スティッキー ビットを使用する方法

スクリプトでのテストの使用

一般的なファイル テストifステートメントは、単純なスクリプト構成です。 二重括弧 ” [[ ]] ” 内の比較では、 -fテストを使用して、その名前の通常のファイルが存在するかどうかを判断します。

このスクリプトのテキストをエディターにコピーして「script1.sh」という名前のファイルに保存し、 chmodを使用して実行可能にします。

 #!/ビン/バッシュ

[[ -f $1 ]] の場合 

それから 

  echo "ファイル $1 は存在します。" 

そうしないと 

  echo "ファイル $1 が見つかりません。" 

フィ

コマンドラインでファイルの名前をスクリプトに渡す必要があります。

 chmod +x script1.sh 

chmod でスクリプトを実行可能にする

この記事の他の例を試す場合は、各スクリプトでこれを行う必要があります。

単純なテキスト ファイルでスクリプトを試してみましょう。

 ./script1.sh テストファイル.txt 

通常のファイルで script1.sh を実行する

ファイルは存在し、スクリプトはその事実を正しく報告します。 ファイルを削除して再試行すると、テストは失敗し、スクリプトはそれを報告するはずです。

 ./script1.sh テストファイル.txt 

存在しないファイルに対して script1.sh を実行する

実際の状況では、スクリプトは適切なアクションを実行する必要があります。 おそらく、エラーにフラグを立てて停止します。 たぶん、ファイルを作成して続行します。 不足しているファイルを置き換えるために、バックアップ ディレクトリから何かをコピーする場合があります。 それはすべて、スクリプトの目的に依存します。 しかし、少なくとも今では、スクリプトはファイルが存在するかどうかに基づいて決定を下すことができます。

-fフラグは、ファイルが存在するかどうか、および「通常の」ファイルであるかどうかをテストします。 つまり、デバイス ファイルなど、ファイルのように見えて実際にはそうではないものです。

ls を使用して「/dev/random」ファイルが存在することを確認し、スクリプトがそれをどのように作成するかを確認します。

 ls -lh /dev/ランダム
./スクリプト/dev/ランダム

デバイス ファイルに対して script1.sh を実行する

このスクリプトは通常のファイルをテストしており、「/dev/random」はデバイス ファイルであるため、テストは失敗します。 多くの場合、ファイルが存在するかどうかを突き止めるには、使用するテストを慎重に選択するか、複数のテストを使用する必要があります。

これは、通常のファイルとキャラクター デバイス ファイルをテストする「script2.sh」です。

 #!/ビン/バッシュ

[[ -f $1 ]] の場合
それから
  echo "ファイル $1 は存在します。"
そうしないと
  echo "ファイル $1 が見つからないか、通常のファイルではありません。"
フィ

[[ -c $1 ]] の場合
それから
  echo "ファイル $1 はキャラクタ デバイス ファイルです。"
そうしないと
  echo "ファイル $1 が見つからないか、特別なファイルではありません。" 
フィ

このスクリプトを「/dev/random」デバイス ファイルで実行すると、最初のテストは想定どおりに失敗し、2 番目のテストは成功します。 ファイルをデバイスファイルとして認識します。

 ./script2.sh /dev/ランダム

キャラクター デバイス ファイルに対して script2.sh を実行する

実際には、キャラクターデバイスファイルとして認識します。 一部のデバイス ファイルはブロック デバイス ファイルです。 現状では、スクリプトはそれらに対応できません。

 ./script2.sh /dev/sda 

ブロック デバイス ファイルに対して scrip2.sh を実行する

論理OR演算子を利用して、2 番目の if ステートメントに別のテストを含めることができます。 今回は、ファイルがキャラクター デバイス ファイルであろうとブロック デバイス ファイルであろうと、テストは true を返します。 これが「script3.sh」です。

 #!/ビン/バッシュ

[[ -f $1 ]] の場合
それから
  echo "ファイル $1 は存在します。"
そうしないと
  echo "ファイル $1 が見つからないか、通常のファイルではありません。"
フィ

[[ -c $1 || の場合-b $1 ]]
それから
  echo "ファイル $1 は文字またはブロック デバイス ファイルです。"
そうしないと
  echo "ファイル $1 が見つからないか、特別なファイルではありません。" 
フィ

このスクリプトは、キャラクター デバイス ファイルとブロック デバイス ファイルの両方を認識します。

 ./script3.sh /dev/ランダム
./script3.sh /dev/sda 

script3.sh が文字およびブロック デバイス ファイルを正しく処理する

さまざまなタイプのデバイス ファイルを区別することが重要な場合は、ネストされたifステートメントを使用できます。 これが「script4.sh」です。

 #!/ビン/バッシュ

[[ -f $1 ]] の場合
それから
  echo "ファイル $1 は存在します。"
そうしないと
  echo "ファイル $1 が見つからないか、通常のファイルではありません。"
フィ

[[ -c $1 ]] の場合
それから
  echo "ファイル $1 はキャラクタ デバイス ファイルです。"
そうしないと
  [[ -b $1 ]] の場合
  それから
    echo "ファイル $1 はブロック デバイス ファイルです。" 
  そうしないと
    echo "ファイル $1 が見つからないか、デバイス ファイルではありません。"
  フィ
フィ

このスクリプトは、キャラクター デバイス ファイルとブロック デバイス ファイルの両方を認識して分類します。

 ./script4.sh /dev/ランダム
./script4.sh /dev/sda 

script8.sh が正しく文字およびブロック デバイス ファイルを識別する

論理 AND 演算子を使用すると、一度に複数の特性をテストできます。 これが「script5.sh」です。 ファイルが存在、スクリプトにそのファイルに対する読み取りおよび書き込み権限があることを確認します。

 #!/ビン/バッシュ

[[ -f $1 && -r $1 && -w $1 ]]
それから
  echo "ファイル $1 が存在し、読み取り/書き込み権限があります。"
そうしないと
  echo "ファイル $1 が見つからないか、通常のファイルではないか、読み取り/書き込みができません。"
フィ

私たちに属するファイルとrootに属するファイルでスクリプトを実行します。

 ./script5.sh .bashrc
 ./script5.sh /etc/fstab 

script5.sh ファイルが存在するかどうか、および読み取りと書き込みのアクセス許可が設定されているかどうかを確認します

ディレクトリの存在をテストするには、 -dテストを使用します。 これが「script6.sh」です。 これはバックアップ スクリプトの一部です。 最初に、コマンドラインで渡されたディレクトリが存在するかどうかを確認します。 論理NOT演算子を使用し! ifステートメントのテストで。

 #!/ビン/バッシュ

もしも [[ ! -d $1 ]]
それから
  echo "バックアップディレクトリを作成しています:" $1
  mkdir $1

  もしも [[ ! $? -eq 0 ]]
  それから
    echo "バックアップ ディレクトリを作成できませんでした:" $1
    出口
  フィ
そうしないと
  echo "バックアップ ディレクトリが存在します。"
フィ

# ファイルのバックアップを続行
echo "バックアップ中: "$1

ディレクトリが存在しない場合は作成します。 ディレクトリ作成ファイルの場合、スクリプトは終了します。 ディレクトリの作成が成功した場合、またはディレクトリがすでに存在する場合、スクリプトはバックアップ アクションを続行します。

スクリプトを実行し、 ls-d (ディレクトリ) オプションを使用して、バックアップ ディレクトリが存在するかどうかを確認します。

 ./script6.sh ドキュメント/プロジェクトのバックアップ
ls -d ドキュメント/プロジェクトのバックアップ

ディレクトリが存在するかどうかを検出するscript6.sh

バックアップ ディレクトリが作成されました。 スクリプトを再度実行すると、ディレクトリが既に存在することが報告されるはずです。

 ./script6.sh 

既存のディレクトリを再利用する script6.sh

スクリプトはディレクトリを見つけ、バックアップの実行に進みます。

推測せずにテストする

遅かれ早かれ、仮定は悪いことが起こることにつながります。 最初にテストし、それに応じて対応します。

知識は力である。 テストを使用して、スクリプトに必要な知識を与えます。

関連: Linux スクリプトが仮想マシンで実行されていることを検出する方法