web-dev-qa-db-fra.com

Vérifier si l'argument passé est un fichier ou un répertoire dans Bash

J'essaie d'écrire un script extrêmement simple dans Ubuntu qui me permettrait de lui transmettre un nom de fichier ou un répertoire, et de pouvoir faire quelque chose de spécifique lorsqu'il s'agit d'un fichier et autre chose lorsqu'il s'agit d'un répertoire. Le problème que je rencontre est lorsque le nom du répertoire, ou probablement des fichiers aussi, contient des espaces ou d’autres caractères d'échappement dans le nom.

Voici mon code de base ci-dessous, et quelques tests.

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

Et voici la sortie:

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

Tous ces chemins sont valides et existent.

107
Andy

Cela devrait fonctionner. Je ne sais pas pourquoi c'est un échec. Vous citez vos variables correctement. Que se passe-t-il si vous utilisez ce script avec le 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

Les doubles crochets sont une extension bash à [ ]. Il n’est pas nécessaire de citer des variables, même si elles contiennent des espaces.

Cela vaut également la peine d'essayer: -e pour tester si un chemin existe sans tester le type de fichier.

143
John Kugelman

Au moins, écrivez le code sans l'arbre touffu:

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

Quand je mets cela dans un fichier "xx.sh" et crée un fichier "xx sh", et l'exécute, je reçois:

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

Étant donné que vous rencontrez des problèmes, vous devez déboguer le script en ajoutant:

ls -l "${PASSED}"

Cela vous montrera ce que ls pense des noms que vous transmettez au script.

9
Jonathan Leffler

Utiliser -f et -d permet d'activer /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
2
Kamran

Une solution plus élégante

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
Jaison John

MISE À JOUR: J'ai été voté, j'ai donc décidé de réécrire ma réponse, merci pour les commentaires. 

Utiliser la commande "fichier" peut être utile pour cela:

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

Exemples de sortie:

$ ./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: les réponses ci-dessus fonctionnent, mais vous pouvez utiliser -s pour vous aider dans des situations étranges en recherchant d'abord un fichier valide:

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

Bon mot

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

le résultat est vrai (0) (dir) ou vrai (0) (fichier) ou faux (1) (ni)

0
nmclough