检查传递的参数是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。仅供参考。

3
@glenn-奇怪的是,变量分配中不需要引号。
John Kugelman

Answers:


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

使用“文件”命令可能对此有用:

#!/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检查的是非空文件,大小为非零)?而且,您是否不会为块特殊,字符特殊,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通常是内置的shell,尽管通常也有诸如/bin/test和的可执行文件/bin/[。)
Jonathan Leffler

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
请回答问题时,您可以添加一些说明吗?
塞巴斯蒂安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 

最好在输出中回显文件名,就像问题中的代码一样。尚不清楚提示输入文件名是否有所改善。该代码不区分文件,目录和“其他”。如果没有答案,或者您有新信息要传达,可以在一个旧问题上添加一个新答案。这里不是这种情况。
乔纳森·莱夫勒

-2

一支班轮

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

结果为true(0)(dir)或true(0)(文件)或false(1)(都不是)


如果替换touch bobmkdir bob,则会得到输出:dirfile两行。
乔纳森·莱夫勒
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.