检查传递的参数是不是是 Bash 中的文件或目录

Posted

技术标签:

【中文标题】检查传递的参数是不是是 Bash 中的文件或目录【英文标题】:Check if passed argument is file or directory in Bash检查传递的参数是否是 Bash 中的文件或目录 【发布时间】:2011-06-07 14:16:08 【问题描述】:

我正在尝试在 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

所有这些路径都是有效的,并且存在。

【问题讨论】:

if-else Bash 中的结构也支持elif。仅供参考。 @glenn - 奇怪的是,变量赋值中不需要引号。 Check if a directory exists in a shell script 可能重复。 【参考方案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

双方括号是[ ] 的 bash 扩展。它不需要引用变量,即使它们包含空格。

也值得一试:-e 测试路径是否存在,而不测试它是什么类型的文件。

【讨论】:

【参考方案2】:

至少写出没有浓密树的代码:

#!/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 -ld "$PASSED"

这将向您展示 ls 对您传递脚本的名称的看法。

【讨论】:

【参考方案3】:

使用-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/[。)【参考方案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 等打印任何诊断信息?符号链接可能会解析到链接远端的内容;损坏的符号链接更成问题。 你有什么建议作为编辑,我没有关注你的评论 使用file--brief 标志。它只是输出directory【参考方案5】:

使用stat

function delete_dir () 
  type="$(stat --printf=%F "$1")"
  if [ $? -ne 0 ]; then
    echo "$1 directory does not exist. Nothing to delete."
  elif [ "$type" == "regular file" ]; then
    echo "$1 is a file, not a directory."
    exit 1
  elif [ "$type" == "directory" ]; then
    echo "Deleting $1 directory."
    rm -r "$1"
  fi


function delete_file () 
  type="$(stat --printf=%F "$1")"
  if [ $? -ne 0 ]; then
    echo "$1 file does not exist. Nothing to delete."
  elif [ "$type" == "directory" ]; then
    echo "$1 is a regular file, not a directory."
    exit 1
  elif [ "$type" == "regular file" ]; then
    echo "Deleting $1 regular file."
    rm "$1"
  fi

https://linux.die.net/man/2/stat https://en.m.wikipedia.org/wiki/Unix_file_types

【讨论】:

【参考方案6】:

更优雅的解决方案

echo "Enter the file name"
read x
if [ -f $x ]
then
    echo "This is a regular file"
else
    echo "This is a directory"
fi

【讨论】:

提示输入而不是使用命令行参数通常不是“更优雅”。您应该在测试中引用变量:if [ -f "$x" ].【参考方案7】:

根据题目回答:

检查传递的参数是 Bash 中的文件还是目录

如果提供的参数有一个斜杠,这也有效。例如dirname/

die()  echo $* 1>&2; exit 1; 
# This is to remove the the slash at the end: dirName/ -> dirName
fileOrDir=$(basename "$1")
( [ -d "$fileOrDir" ] || [ -f "$fileOrDir" ] ) && die "file or directory  $fileOrDir already exists"

测试:

mkdir mydir
touch myfile

command dirName
# file or directory  mydir already exists
command dirName/
# file or directory  mydir already exists
command filename
# file or directory  myfile already exists

【讨论】:

【参考方案8】:
#!/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 

【讨论】:

最好在输出中回显文件名,就像问题中的代码一样。目前尚不清楚提示输入文件名是否是一种改进。该代码不区分文件、目录和“其他”。如果没有答案,或者您有新信息要传递,可以为旧问题添加新答案。这不是这里的情况。【参考方案9】:

一个班轮

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

结果为真(0)(dir)或真(0)(文件)或假(1)(两者都不是)

【讨论】:

如果我将touch bob 替换为mkdir bob,我会得到两行输出:dirfile【参考方案10】:

这应该可行:

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

【讨论】:

拜托,你可以在回答问题时添加一些解释吗?

以上是关于检查传递的参数是不是是 Bash 中的文件或目录的主要内容,如果未能解决你的问题,请参考以下文章

确定字符串输入是不是可以是 Python 中的有效目录

bash:以空格作为参数传递路径?

在 Bash 的文件路径参数中获取最后一个目录名/文件名

如何将“=”作为参数的一部分从 Windows 的 bit-bash 传递给 .cmd 或 .bat 文件

TCL/Expect 相当于 Bash $@ 或如何将参数传递给 TCL/Expect 中的衍生进程

Bash - 从与脚本文件位于同一目录中的文件读取