渡された引数がBashのファイルまたはディレクトリかどうかを確認します


156

Ubuntuで非常に単純なスクリプトを記述しようとしています。これにより、ファイル名またはディレクトリのいずれかを渡して、ファイルの場合は特定の処理を行い、ディレクトリの場合は別の処理を行うことができます。私が抱えている問題は、ディレクトリ名、またはおそらくファイルも、名前にスペースまたは他の回避可能な文字が含まれている場合です。

以下に、私の基本的なコードといくつかのテストを示します。

#!/bin/bash

PASSED=$1

if [ -d "${PASSED}" ] ; then
    echo "$PASSED is a directory";
else
    if [ -f "${PASSED}" ]; then
        echo "${PASSED} is a file";
    else
        echo "${PASSED} is not valid";
        exit 1
    fi
fi

そしてここに出力があります:

andy@server~ $ ./scripts/testmove.sh /home/andy/
/home/andy/ is a directory

andy@server~ $ ./scripts/testmove.sh /home/andy/blah.txt
/home/andy/blah.txt is a file

andy@server~ $ ./scripts/testmove.sh /home/andy/blah\ with\ a\ space.txt
/home/andy/blah with a space.txt is not valid

andy@server~ $ ./scripts/testmove.sh /home/andy\ with\ a\ space/
/home/andy with a space/ is not valid

これらのパスはすべて有効であり、存在します。


5
if- elseバッシュ中の構築もサポートelif。参考までに。

3
@glenn-奇妙なことに、変数の割り当てでは引用符は必要ありません。
John Kugelman、2011

回答:


211

うまくいくはずです。なぜ失敗するのかわかりません。変数を適切に引用しています。このスクリプトをdoubleで使用するとどうなります[[ ]]か?

if [[ -d $PASSED ]]; then
    echo "$PASSED is a directory"
elif [[ -f $PASSED ]]; then
    echo "$PASSED is a file"
else
    echo "$PASSED is not valid"
    exit 1
fi

二重角括弧はのbash拡張[ ]です。変数にスペースが含まれていても、変数を引用符で囲む必要はありません。

また、試してみる価値が-eあります。ファイルの種類をテストせずにパスが存在するかどうかをテストします。


9

少なくともふさふさした木のないコードを書いてください:

#!/bin/bash

PASSED=$1

if   [ -d "${PASSED}" ]
then echo "${PASSED} is a directory";
elif [ -f "${PASSED}" ]
then echo "${PASSED} is a file";
else echo "${PASSED} is not valid";
     exit 1
fi

それをファイル "xx.sh"に入れてファイル "xx sh"を作成し、実行すると、次のようになります。

$ cp /dev/null "xx sh"
$ for file in . xx*; do sh "$file"; done
. is a directory
xx sh is a file
xx.sh is a file
$

問題が発生している場合は、以下を追加してスクリプトをデバッグする必要があります。

ls -l "${PASSED}"

これによりls、スクリプトに渡した名前をどう考えるかがわかります。


4

これには「file」コマンドを使用すると便利です。

#!/bin/bash
check_file(){

if [ -z "${1}" ] ;then
 echo "Please input something"
 return;
fi

f="${1}"
result="$(file $f)"
if [[ $result == *"cannot open"* ]] ;then
        echo "NO FILE FOUND ($result) ";
elif [[ $result == *"directory"* ]] ;then
        echo "DIRECTORY FOUND ($result) ";
else
        echo "FILE FOUND ($result) ";
fi

}

check_file "${1}"

出力例:

$ ./f.bash login
DIRECTORY FOUND (login: directory) 
$ ./f.bash ldasdas
NO FILE FOUND (ldasdas: cannot open `ldasdas' (No such file or  directory)) 
$ ./f.bash evil.php 
FILE FOUND (evil.php: PHP script, ASCII text) 

参考までに:上記の回答は機能しますが、まず-sを使用して、まず有効なファイルを確認することにより、奇妙な状況を支援できます。

#!/bin/bash

check_file(){
    local file="${1}"
    [[ -s "${file}" ]] || { echo "is not valid"; return; } 
    [[ -d "${file}" ]] && { echo "is a directory"; return; }
    [[ -f "${file}" ]] && { echo "is a file"; return; }
}

check_file ${1}

それで、空のファイルは有効ではありません(-sサイズが0以外の空でないファイルをチェックするため)?また、ブロックスペシャル、キャラクタースペシャル、FIFOなどの診断を出力しませんか?シンボリックリンクはおそらくリンクの遠端にあるものに解決されます。壊れたシンボリックリンクはさらに問題があります。
ジョナサンレフラー

編集としてあなたは何を提案しますか、私はあなたのコメントに従っていません
Mike Q

--briefフラグを使用しfileます。ただ出力directoryするだけです。
Berkant Ipek

2

の使用-f-dスイッチオン/bin/test

F_NAME="${1}"

if test -f "${F_NAME}"
then                                   
   echo "${F_NAME} is a file"
elif test -d "${F_NAME}"
then
   echo "${F_NAME} is a directory"
else                                   
   echo "${F_NAME} is not valid"
fi

一般的に言えば、同等の回答がすでに利用可能な場合は、わざわざ古い質問に新しい回答を追加するべきではありません。追加する驚くべき新しい情報がある場合でも、必ず答えてください。しかし、あなたが言ったことはすでに言われています。(test通常、などの実行があるが、通常、内蔵シェルであり/bin/test、また、/bin/[。)
ジョナサン・レフラー

1

よりエレガントなソリューション

echo "Enter the file name"
read x
if [ -f $x ]
then
    echo "This is a regular file"
else
    echo "This is a directory"
fi

2
コマンドライン引数を使用する代わりに入力を要求することは、通常「よりエレガント」ではありません。テストでは変数を引用する必要があります:if [ -f "$x" ]
ジョナサンレフラー

1
function check_file_path(){
    [ -f "$1" ] && return
    [ -d "$1" ] && return
    return 1
}
check_file_path $path_or_file


-2
#!/bin/bash                                                                                               
echo "Please Enter a file name :"                                                                          
read filename                                                                                             
if test -f $filename                                                                                      
then                                                                                                      
        echo "this is a file"                                                                             
else                                                                                                      
        echo "this is not a file"                                                                         
fi 

問題のコードと同じように、出力にファイル名をエコーするのが最善です。ファイル名を要求することが改善であることは明らかではありません。コードは、ファイル、ディレクトリ、および「その他」を区別しません。回答がない場合、または伝える必要のある新しい情報がある場合は、古い質問に新しい回答を追加してもかまいません。ここではそうではありません。
ジョナサンレフラー

-2

一発ギャグ

touch bob; test -d bob && echo 'dir' || (test -f bob && echo 'file')

結果はtrue(0)(dir)またはtrue(0)(file)またはfalse(1)(どちらでもない)


私が交換した場合touch bobmkdir bob、私は出力が得られますdirし、file2行に。
ジョナサンレフラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.