Kiểm tra xem đối số được truyền là tệp hoặc thư mục trong Bash


156

Tôi đang cố gắng viết một tập lệnh cực kỳ đơn giản trong Ubuntu để cho phép tôi chuyển nó thành tên tệp hoặc thư mục và có thể thực hiện một cái gì đó cụ thể khi đó là tệp và một thứ khác khi đó là thư mục. Vấn đề tôi gặp phải là khi tên thư mục, hoặc có thể là các tệp cũng có dấu cách hoặc các ký tự có thể thoát được khác trong tên.

Đây là mã cơ bản của tôi dưới đây, và một vài thử nghiệm.

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

Và đây là đầu ra:

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

Tất cả những con đường đó là hợp lệ, và tồn tại.


5
if- elsecấu trúc trong Bash cũng hỗ trợ elif. Chỉ cần FYI.

3
@glenn - Thật kỳ lạ, trích dẫn không bắt buộc trong các bài tập biến.
John Kugelman

Câu trả lời:


211

Cần làm việc. Tôi không chắc tại sao nó thất bại. Bạn đang trích dẫn các biến của bạn đúng. Điều gì xảy ra nếu bạn sử dụng tập lệnh này với gấp đôi [[ ]]?

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

Dấu ngoặc vuông là một phần mở rộng bash để [ ] . Nó không yêu cầu các biến được trích dẫn, ngay cả khi chúng có chứa khoảng trắng.

Cũng đáng thử: -eđể kiểm tra nếu một đường dẫn tồn tại mà không kiểm tra loại tệp đó là gì.


9

Ít nhất là viết mã mà không có cây bụi:

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

Khi tôi đặt nó vào một tệp "xx.sh" và tạo một tệp "xx sh" và chạy nó, tôi nhận được:

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

Cho rằng bạn đang gặp vấn đề, bạn nên gỡ lỗi tập lệnh bằng cách thêm:

ls -l "${PASSED}"

Điều này sẽ cho bạn thấy những gì bạn lsnghĩ về tên bạn vượt qua kịch bản.


4

Sử dụng lệnh "file" có thể hữu ích cho việc này:

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

Ví dụ đầu ra:

$ ./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: các câu trả lời ở trên hoạt động nhưng bạn có thể sử dụng -s để trợ giúp trong các tình huống kỳ lạ bằng cách kiểm tra tệp hợp lệ trước:

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

Vì vậy, các tệp trống không hợp lệ (vì -skiểm tra tệp không trống, tệp có kích thước khác không)? Và bạn sẽ không in bất kỳ chẩn đoán nào cho một khối đặc biệt, nhân vật đặc biệt, FIFO, v.v? Symlinks có thể giải quyết những gì ở cuối liên kết; symlink bị hỏng có nhiều vấn đề hơn.
Jonathan Leffler

Bạn gợi ý điều gì khi chỉnh sửa, tôi không theo dõi bình luận của bạn
Mike Q

Sử dụng --briefcờ của file. Nó chỉ đơn thuần là đầu ra directorykhi nó được.
Berkant Ipek

2

Sử dụng -f-dbật /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

Nói chung, bạn không nên thêm câu trả lời mới vào câu hỏi cũ khi đã có sẵn câu trả lời tương đương. Nếu bạn có một số thông tin mới đáng giật mình để thêm, nhưng tất cả có nghĩa là đưa ra câu trả lời. Nhưng những gì bạn đã nói đã được nói. ( testthường là một vỏ được tích hợp sẵn, mặc dù thường cũng có một tệp thực thi như /bin/test, và cả /bin/[.)
Jonathan Leffler

1

Một giải pháp thanh lịch hơn

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
Nhắc nhở cho đầu vào thay vì sử dụng đối số dòng lệnh thường không "thanh lịch" hơn. Bạn nên trích dẫn biến trong bài kiểm tra : if [ -f "$x" ].
Jonathan Leffler

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

-1

Công việc này sẽ:

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

2
Xin vui lòng, bạn có thể thêm một số giải thích khi bạn trả lời một câu hỏi?
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 

Tốt nhất là lặp lại tên tệp trong đầu ra, như mã trong câu hỏi. Không rõ ràng rằng việc nhắc tên tệp là một sự cải tiến. Mã không phân biệt giữa các tệp, thư mục và 'khác'. Bạn có thể thêm câu trả lời mới vào câu hỏi cũ nếu không có câu trả lời hoặc bạn có thông tin mới để truyền đạt. Đó không phải là trường hợp ở đây.
Jonathan Leffler

-2

Lót

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

kết quả là đúng (0) (dir) hoặc true (0) (tệp) hoặc sai (1) (không)


Nếu tôi thay thế touch bobbằng mkdir bob, tôi nhận được đầu ra: dirfiletrên hai dòng.
Jonathan Leffler
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.