如果存在特定文件,则显示任意消息的命令


11

如果存在特定文件,是否有命令显示消息“是”?如果文件不存在,则无需提供功能。

Answers:


25

使用以下简单的Bash单行代码:

if [ -e FILENAME ] ; then echo Yes ; fi

无论-e是否FILENAME存在(文件,目录,链接,设备等),该检查的结果均为true 。

如果只想检查常规文件,请使用@Arronical所说的-f代替。


18
[ -e FILENAME ] && echo Yes
Zeb McCorkle

@ZebMcCorkle正确,也可以。您可以将其作为单独的答案发布。
字节指挥官

3
如果FILENAME是变量扩展,或包含任何特殊字符,则不要忘记引用它。例如在脚本中[ -e "$1" ] && echo Yes
彼得·科德斯

@PeterCordes,如果您使用的是bash,则可以使用[[]]不是引用变量。
Holloway

1
@Holloway:是的,但是有时您需要编写仅需要POSIX sh的可移植脚本。这就是为什么我给出了一个安全的版本,而不是对其进行投票和对bash答复进行投票。还要注意,在内部引用扩展并不是问题[[ ]],对于不记得[[ ]]运算符内部或算术上下文特殊规则的初学者而言,始终引用是个好习惯。
彼得·科德斯

10

您可以使用以下简单脚本:

#!/bin/bash

if [[ -f $1 ]]; then
    echo "Yes"
    exit 0
else
    exit 1
fi

另存为file-exists.sh。然后,在终端中,键入chmod +x file-exists.sh

像这样使用:用您要检查的文件./file-exists.sh FILE替换FILE,例如:

./file-exists.sh file.txt

如果file.txt存在,Yes将被打印到终端,并且程序将以状态0(成功)退出。如果该文件不存在,则不会打印任何内容,并且程序将以状态1(失败)退出。

如果您想知道为什么要包含该exit命令,请继续阅读...


有什么用的最多exit的命令?

exit导致正常的进程终止。基本上,这意味着什么:它会停止脚本。它接受一个可选的(数字)参数,该参数将是调用它的脚本的退出状态。

此退出状态使您的其他脚本可以使用您的file-exists脚本,这是它们知道文件是否存在的方式。

一个简单的示例可以使用此脚本(将其另存为file-exists-cli.sh):

#!/bin/bash

echo "Enter a filename and I will tell you if it exists or not: "
read FILE
# Run `file-exists.sh` but discard any output because we don't need it in this example
./file-exists.sh $FILE &>> /dev/null
# #? is a special variable that holds the exit status of the previous command
if [[ $? == 0 ]]; then
    echo "$FILE exists"
else
    echo "$FILE does not exist"
fi

照常执行chmod +x file-exists-cli.sh,然后运行它:./file-exists-cli.sh。您会看到以下内容:

文件存在(exit 0):

➜  ~ ./file-exists-cli.sh 
Enter a filename and I will tell you if it exists or not: 
booleans.py
booleans.py exists

文件不存在(exit 1):

➜  ~ ./file-exists-cli.sh
Enter a filename and I will tell you if it exists or not: 
asdf
asdf does not exist

2
很好,但是您应该引用变量引用,例如"$1"。如果其中有空格,它将在没有引号的情况下中断,并且可能发生其他不良情况。

9

在命令行上的bash shell中。

if [[ -f /path/to/file ]]; then echo "Yes"; fi

这将使用bash条件运算符-f,并正在检查文件是否存在以及是否为常规文件。如果要测试任何文件,包括目录和链接,请使用-e

这是bash条件的重要资源。


1
为什么要用大括号?
字节指挥官

1
我不喜欢test它的原始格式,我知道这太过分了,但这是我的习惯。
Arronical '16

7
@ByteCommander:双括号通常比单括号更好。它们是shell语法的一部分(而不是调用[命令(通常调用内置命令)。)它们纠正了单个大括号版本的不一致和不正确的行为。[内置仍然是为了兼容性,但是我看不出有什么充分的理由在新的bash代码中使用它。(如果您需要编写可在古老的外壳或类似的东西上运行的POSIX兼容脚本,则有所不同。)
Nick Matteo

@kundor:为了公平起见,大多数人都同意,“ [通常称为内置”是可疑的。type -a [对我来说,列出“ shell内置”,然后列出“ /usr/bin/[。”
wchargin

1
@wchargin:恐怕我不明白你在说什么。您的type结果似乎证实了我的意思,不是吗?
Nick Matteo

5

做您想做的最短的命令是:

test -e FILENAME && echo Yes

test -e将测试给定名称在文件系统中是否存在。(您可以用来test -f仅限制为常规文件。有关man test更多信息,请参阅。)

如果给定的条件评估为true,则test返回成功退出状态(否则返回失败状态)。我们使用组合这两个命令&&,这意味着“如果前一个命令以成功状态退出,则执行下一个命令”。下一条命令只是Yes在标准输出上打印;如果是交互式外壳,则在终端上。

这避免了if语句的其他文本材料,但给出了相同的结果。当仅涉及单个命令时&&,使用(或相反||)将命令绑定在一起非常有效。如果您想要做的不仅仅是响应单个命令的退出状态而执行单个命令,那么使用该if语法将变得更加易读。

正如其他答案中已经指出的那样,等效的if样式构造应为:

if test -e FILENAME; then echo Yes; fi

或者:

if test -e FILENAME
then
    echo Yes
fi

为了这些目的,[test是等效的,所不同的是[要求的终接]


4

要解决此类问题,可以采用多种方法,这是另一种方法:使用find-execflag的命令。文件的路径可以分为两部分find /etc,分别设置目录和-name FILENAME指定文件名(duh!)。-maxdepth只会继续find使用/etc目录,而不会进入子目录

adminx@L455D:~$ find /etc -maxdepth 1  -name passwd -exec printf "YES\n" \;
YES
adminx@L455D:~$ find /etc -maxdepth 1  -name passwd1 -exec printf "YES\n" \;
adminx@L455D:~$ 

另一种方式,通过stat

adminx@L455D:~$ stat /etc/passwd1 &>/dev/null && echo YES
adminx@L455D:~$ stat /etc/passwd &>/dev/null && echo YES
YES

或者通过python:

>>> import os
>>> if os.stat('/etc/passwd'): 
...    print 'YES'
... 
YES
>>> if os.stat('/etc/passwd1'): 
...    print 'YES'
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory: '/etc/passwd1'

或简短的命令行替代:

 python -c "from os.path import exists; print 'Yes' if exists('/etc/fstab') else '' "
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.