Перевірте, чи переданий аргумент є файлом чи каталогом у 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конструкції в Bash також підтримують elif. Просто FYI.

3
@glenn - Цікаво, що лапки в змінних призначеннях не потрібні.
Джон Кугельман

Відповіді:


211

Це має спрацювати. Я не впевнений, чому це не вдається. Ви правильно цитуєте свої змінні. Що станеться, якщо використовувати цей сценарій з подвійним [[ ]]?

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

Подвійні квадратні дужки - це баш розширення до [ ]. Він не вимагає цитування змінних, навіть якщо вони містять пробіли.

Також варто спробувати: -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

Використання команди "файл" може бути корисним для цього:

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

FYI: відповіді вище працюють, але ви можете використовувати -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перевірка на непорожній файл, один із ненульовим розміром)? І ви не надрукуєте жодного діагнозу для спеціального блоку, спеціального символу, FIFO тощо? Символьні посилання, ймовірно, вирішують те, що знаходиться в дальній частині посилання; зламані символьні посилання є більш проблематичними.
Джонатан Леффлер

Що ви пропонуєте як редагування, я не слідкую за вашим коментарем
Майк Q

Використовуйте --briefпрапор file. Він просто видає, directoryколи є.
Беркант Іпек

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

-1

Це має працювати:

#!/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
Будь ласка, чи можете ви додати деякі пояснення, відповідаючи на запитання?
Себастьян Темпрадо

-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')

результат істинний (0) (dir) або true (0) (файл) або false (1) (ні)


Якщо я заміню touch bobна mkdir bob, я отримую вихід: dirі fileв двох рядках.
Джонатан Леффлер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.