Periksa apakah argumen yang diteruskan adalah file atau direktori di Bash

156

Saya mencoba untuk menulis skrip yang sangat sederhana di Ubuntu yang memungkinkan saya untuk memberikannya nama file atau direktori, dan dapat melakukan sesuatu yang spesifik ketika itu file, dan sesuatu yang lain ketika itu adalah direktori. Masalah yang saya alami adalah ketika nama direktori, atau mungkin file juga, memiliki spasi atau karakter lain yang dapat dihapus dalam nama.

Ini kode dasar saya di bawah, dan beberapa tes.

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

Dan inilah hasilnya:

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

Semua jalur itu valid, dan ada.

Andy
sumber
5
if- elseKonstruksi di Bash juga mendukung elif. Hanya FYI.
3
@glenn - Anehnya, kutipan tidak diperlukan dalam penugasan variabel.
John Kugelman

Jawaban:

211

Itu seharusnya bekerja. Saya tidak yakin mengapa itu gagal. Anda mengutip variabel Anda dengan benar. Apa yang terjadi jika Anda menggunakan skrip ini dengan ganda [[ ]]?

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

Kurung kotak ganda adalah ekstensi bash ke [ ]. Itu tidak memerlukan variabel untuk dikutip, bahkan jika mereka mengandung spasi.

Juga patut dicoba: -euntuk menguji apakah ada jalur tanpa menguji jenis file apa itu.

John Kugelman
sumber
9

Setidaknya tulis kode tanpa pohon lebat:

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

Ketika saya meletakkannya di file "xx.sh" dan membuat file "xx sh", dan menjalankannya, saya mendapatkan:

$ 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
$

Karena Anda mengalami masalah, Anda harus men-debug skrip dengan menambahkan:

ls -l "${PASSED}"

Ini akan menunjukkan kepada Anda apa yang lsdipikirkan tentang nama-nama yang Anda lewati skrip.

Jonathan Leffler
sumber
4

Menggunakan perintah "file" mungkin berguna untuk ini:

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

Contoh keluaran:

$ ./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) 

FYI: jawaban di atas berfungsi tetapi Anda dapat menggunakan -s untuk membantu dalam situasi aneh dengan memeriksa file yang valid terlebih dahulu:

#!/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}
Mike Q
sumber
Jadi, file kosong tidak valid (karena -smemeriksa file tidak kosong, file dengan ukuran tidak nol)? Dan Anda tidak akan mencetak diagnosis untuk blok spesial, karakter spesial, FIFO, dll? Symlinks mungkin memutuskan apa yang ada di ujung tautan; symlink yang rusak lebih bermasalah.
Jonathan Leffler
Apa yang Anda sarankan sebagai suntingan, saya tidak mengikuti komentar Anda
Mike Q
Gunakan --briefbendera file. Itu hanya keluaran directoryketika itu.
Berkant Ipek
2

Menggunakan -fdan -dmengaktifkan /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
Kamran
sumber
Secara umum, Anda tidak perlu repot-repot menambahkan jawaban baru ke pertanyaan lama ketika sudah ada jawaban yang setara. Jika Anda memiliki beberapa informasi baru yang mengejutkan untuk ditambahkan, tetapi semua cara memberikan jawaban. Tapi apa yang Anda katakan sudah dikatakan. ( testBiasanya shell adalah built-in, meskipun biasanya juga ada executable seperti /bin/test, dan juga /bin/[.)
Jonathan Leffler
1

Solusi yang lebih elegan

echo "Enter the file name"
read x
if [ -f $x ]
then
    echo "This is a regular file"
else
    echo "This is a directory"
fi
Jaison John
sumber
2
Meminta input alih-alih menggunakan argumen baris perintah biasanya tidak "lebih elegan". Anda harus mengutip variabel dalam ujian: if [ -f "$x" ].
Jonathan Leffler
1
function check_file_path(){
    [ -f "$1" ] && return
    [ -d "$1" ] && return
    return 1
}
check_file_path $path_or_file
张馆长
sumber
-1

Ini harus bekerja:

#!/bin/bash

echo "Enter your Path:"
read a

if [[ -d $a ]]; then 
    echo "$a is a Dir" 
elif [[ -f $a ]]; then 
    echo "$a is the File" 
else 
    echo "Invalid path" 
fi
pengguna11791326
sumber
2
Tolong, bisakah Anda menambahkan beberapa penjelasan saat Anda menjawab pertanyaan?
Sébastien Temprado
-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 
muj
sumber
Sebaiknya gema nama file dalam output, seperti kode dalam pertanyaan. Tidak jelas bahwa meminta nama file adalah peningkatan. Kode tidak membedakan antara file, direktori, dan 'lainnya'. Tidak apa-apa untuk menambahkan jawaban baru ke pertanyaan lama jika tidak ada jawaban, atau Anda memiliki informasi baru untuk disampaikan. Bukan itu masalahnya di sini.
Jonathan Leffler
-2

Satu liner

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

hasilnya benar (0) (dir) atau benar (0) (file) atau salah (1) (tidak ada)

noelmcloughlin
sumber
Jika saya ganti touch bobdengan mkdir bob, saya mendapatkan output: dirdan filepada dua baris.
Jonathan Leffler