4468

什么命令检查Bash shell脚本中是否存在目录?

0

35个答案35

重置为默认值
6018

要检查目录是否存在:

如果[-d“$DIRECTORY”];然后echo“$DIRECTORY确实存在。”fi(菲涅耳)

要检查目录是否不存在:

如果[!-d“$DIRECTORY”];然后echo“$DIRECTORY不存在。”fi(菲涅耳)

然而,作为乔恩·埃里克森指出,如果没有考虑到指向目录的符号链接也会通过此检查,则后续命令可能无法按预期工作。例如,运行以下命令:

ln-s“$ACTUAL_DIR”“$SYMLINK”如果[-d“$SYMLINK”];然后rmdir“$SYMLINK”fi(菲涅耳)

将生成错误消息:

rmdir:未能删除“symlink”:不是目录

因此,如果后续命令需要目录,则可能必须以不同的方式处理符号链接:

如果[-d“$LINK_OR_DIR”];然后如果[-L“$LINK_OR_DIR”];然后#这是一个符号链接!#此处显示特定于符号链接的命令。rm“$LINK_OR_DIR”其他的#这是一个目录!#此处显示目录命令。rmdir“$LINK_OR_DIR”fi(菲涅耳)fi(菲涅耳)

特别注意用于包装变量的双引号。原因由8jean解释在另一个答案中.

如果变量包含空格或其他异常字符,则可能会导致脚本失败。

16
  • 43
    如果您想安全地使用GNU工具,请使用--强烈建议(选项结束标记)。否则,如果您的变量包含看起来像选项的内容,那么脚本将像使用空格一样失败。 评论 2009年7月21日16:36
  • 4
    对于bash、ksh等的现代版本,[…]是一个内置的 评论 2011年3月24日14:22
  • 98
    要记住一件事:[!-d“$DIRECTORY”]如果$目录不存在,或者如果存在但不是目录。考虑一下这样的事情如果[!-d“$DIRECTORY”];然后是mkdir“$DIRECTORY”;fi(菲涅耳); 如果“$DIRECTORY”($目录)是一个文件。(当然你应该检查mkdir公司无论如何都成功了;它失败的原因有很多。) 评论 2011年8月9日23:46
  • 10
    值得一提的是,一旦执行了检查,由于其他流程,情况可能已经发生了变化。在许多情况下,最好只创建或使用目录并对故障作出反应。
    – 阿尔夫
    评论 2013年9月9日11:51
  • 20
    而不是同时测试两个目录(-d日)和符号链接(-L(左)),只需在变量后面加一个斜杠就可以了,比如如果[-d“${THING:+$THING/}”]。目录不会介意额外的斜线。文件的计算结果为false。空将保持空,所以是假的。符号链接将解析为其目标。当然,这取决于你的目标。如果你想好了,这很好。如果你想删除它,则此答案中的代码更好。
    – 戈蒂
    评论 2017年1月17日9:21
626

在Bash脚本中引用变量时,总是用双引号将其括起来。

如果[-d“$DIRECTORY”];然后#如果$DIRECTORY存在,即使它包含空格,也将在此处输入fi(菲涅耳)

现在的孩子们在他们的目录名中添加了空格和许多其他有趣的字符。(共享空间!在我的时代,我们没有特别的共享空间!)总有一天,其中一个孩子会用你的脚本$目录设置为“我的M0viez”然后你的剧本就会爆炸。你不想那样。所以使用双引号。

14
  • 22
    使用双引号的另一个原因是,由于某些原因没有设置$DIRECTORY。 评论 2008年9月15日22:41
  • 6
    “始终在bash脚本中用双引号将变量括起来……”对于bash,在使用[[…]]时没有技术上的必要;看见tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS(注意:没有分词):“[[和]]之间没有文件名扩展或分词,但有参数扩展和命令替换。”
    – 迈克尔
    评论 2014年9月12日1:31
  • 4
    Unix/Linux上的目录不应该有任何空格,随后脚本也不应该适应它。Windows支持它已经够糟糕了,Windows脚本也会受到影响,但请不要引入不必要的要求。 评论 2014年12月24日13:57
  • 32
    @tvCa我发现,用户通常更喜欢在目录名中获得更大的灵活性,而不是被迫让开发人员更容易操作。(事实上,当处理长文件名时,我发现没有空格的文件名很痛苦,因为这会扼杀换行,尽管我自己过去也曾因在脚本和程序中不考虑带空格的路径而遭受痛苦。) 评论 2015年8月12日15:52
  • 8
    哈。空格只是通常没有符号的字符。无论如何,你可以用反斜杠来避开它们。 评论 2016年10月18日8:27
263

请注意-d日测试可以产生一些令人惊讶的结果:

ln-s tmp/t美元$if[-d t];然后是rmdir t;fi(菲涅耳)rmdir:目录“t”:路径组件不是目录

文件位于:“什么时候目录不是目录?”答案是:“当它是指向目录的符号链接时。”

如果[-d t];然后如果[-L t];然后远程监控其他rmdir t(rmdir目录)fi(菲涅耳)fi(菲涅耳)

您可以在Bash手册中找到更多信息Bash条件表达式[内建命令[[复合命令.

1
  • 15
    或者,假设只需要处理目录(并且可以忽略链接)=>如果[-d tmpdir-a!-L tmpdir];则echo“是目录”;rmdir tmpdir;fi(菲涅耳)…或者,对于同时在链接和目录上工作的一个命令:rm-r tmpdir
    – 迈克尔
    评论 2014年9月12日1:47
252

我找到了双托架的版本测试使编写逻辑测试更加自然:

如果[[-d“${DIRECTORY}”&&!-L“$}目录}”]];然后echo“这是一个bona-fide目录”fi(菲涅耳)

对于的含义-L(左)和其他条件表达式,请参阅Bash参考文档:6.4 Bash条件表达式.

9
  • 对于如果[[-d“$TARFILE”]]我找不到[[: 评论 2011年6月19日14:48
  • 19
    @乡村白痴和@Hedgehog,你在用bash shell吗?双括号不是普遍支持的。关于这一点,这里有一个SO的答案:stackoverflow.com/questions/669452/…
    – 育空人
    评论 2011年7月2日14:54
  • 9
    在Busybox ash中使用默认编译选项[[ ]]支持,但实际上不提供任何不同的功能[ ]如果担心可移植性,请坚持[ ]并使用必要的解决方法。 评论 2012年5月31日15:34
  • 9
    …如果在shell脚本中使用bash构造,那么脚本的第一行应该是:#/bin/bash(而不是#!/bin/sh、ksh等)
    – 迈克尔
    评论 2014年9月12日1:23
  • 5
    在bash中使用双方括号时,不需要引用变量。
    – 雨果·G
    评论 2017年8月11日5:58
227

较短形式:

#如果$DIR是一个目录,则打印yes[-d“$DIR”]&&echo“是”
5
  • 11
    这是这样工作的吗:如果$dir是dir,则回显“yes”? 稍作解释会有所帮助:) 评论 2016年8月5日7:38
  • 9
    命令和其他是一个常用的缩写如果cmd;然后是其他;fi(菲涅耳)--这适用于支持布尔逻辑的大多数编程语言,称为短路求值.
    – 三人组
    评论 2016年10月5日4:03
  • 8
    下的行为不同集合-e(这是一个shell编程最佳实践).
    – 漏斗
    评论 2018年7月23日12:40
  • @杜尔门[-d“$DIR”]被选中(后跟&&echo是),所以我相信集合-e对脚本行为没有影响(即,如果测试失败,脚本将正常继续)。
    – 藏族
    评论 2018年9月4日16:03
  • @杜尔门那不正确。下的行为完全相同集合-e。但如果回声失败,脚本将退出。[-d“$DIR”]单独(否&&命令。。。)将导致脚本退出集合-e,如果测试失败(即目录不存在,或$DIR(美元)存在但不是目录)。
    – 
    评论 2022年7月18日10:40
157
  1. 测试目录或文件是否存在的简单脚本:

    if[-d/home/ram/dir]#对于文件“if[-f/home/rama/file]”然后echo“目录存在”其他的echo“目录不存在”fi(菲涅耳)
  2. 检查目录是否存在的简单脚本:

    mkdir tempdir#如果要检查文件,请使用touch而不是mkdirret=美元?如果[“$ret”==“0”]然后echo“目录存在”其他的echo“目录不存在”fi(菲涅耳)

    上述脚本将检查目录是否存在

    $?如果最后一个命令成功,则返回“0”,否则返回非零值。假设临时目录已存在。然后mkdir临时目录将给出如下错误:

    mkdir:无法创建目录“tempdir”:文件存在

  • 8
    第二个将创建目录,如果它最初不存在的话。那么它不是幂等的。 评论 2019年3月6日6:47
  • 2
    👆👆👆. 第二个看起来很危险。因为它创建了目录,所以目录不存在已经不再是事实了。
    – 克里斯
    评论 2020年2月7日21:38
  • mkdir也不会创建完整的路径(没有param),但相反的情况会更危险,因为您甚至无法恢复(rm-f)更改,因为您不知道它创建了哪些目录
    – 鹿肉
    评论 2021年3月23日23:19
147

要检查目录是否存在,可以使用简单的如果结构如下:

if[-d目录/目录路径];然后#要做的事情else#如果需要#另外:elif[new condition]#要做的事情fi(菲涅耳)

你也可以用否定的方式:

if[!-d目录/目录路径];然后#当没有现有目录时要做的事情

注释:小心。在左大括号和右大括号的两侧留出空白。

使用相同的语法,您可以使用:

-e: 任何类型的档案-f: 文件-h: 符号链接-r: 可读文件-w: 可写文件-x: 可执行文件-s: 文件大小大于零
2
  • 除了使用文件切换偏离主题之外,这怎么会比2008年公认的答案更好呢? 评论 2020年3月5日13:14
  • 更好,因为[!-d目录/目录路径] 评论 2020年3月27日19:46
111

你可以使用测试-d(请参见人体试验).

-d文件如果文件存在并且是目录,则为True。

例如:

test-d“/etc”&&echo存在||echo不存在

注:测试命令与条件表达式相同[(参见:人[),因此它可以跨shell脚本移植。

[-这是测试内置,但最后一个参数必须是文本],以匹配开口[.

有关可能的选项或进一步的帮助,请检查:

  • 帮助[
  • 帮助测试
  • 人体试验人[
62

或者对于完全无用的东西:

[-d.]||echo“否”
1
  • 9
    它永远不会打印“否”。除非被其他线程或其他方式删除,否则当前目录始终存在。
    – 贾希德
    评论 2015年4月19日0:49
61

这里有一个非常实用的成语:

(cd$dir)||return#这是一个目录吗,#我们有通道吗?

我通常将其包装在函数中:

可以使用_as_dir(){(cd${1:需要路径名})|return}

或者:

资产_目录_访问(){(cd${1:需要路径名})||退出}

这种方法的优点是我不必考虑好的错误消息。

光盘会给我一条标准的单行消息标准误差已经。它还将提供我无法提供的更多信息。通过执行光盘在子壳内( ... ),该命令不会影响调用方的当前目录。如果目录存在,则此子shell和函数只是一个no-op。

接下来是我们传递给的论点光盘:需要${1:?路径名}这是一种更为复杂的参数替换形式,下文将对此进行更详细的解释。

Tl;dr:如果传入该函数的字符串为空,我们再次退出子shell( ... )并从函数返回给定的错误消息。


引用93肯尼亚先令手册页:

${参数:?字}

如果参数设置为非空,然后替换其值;否则,打印单词并退出shell(如果不是交互式的)。如果单词则打印标准消息。

如果结肠:从上述表达式中省略,则shell只检查是否设置了参数。

这里的措辞是shell文档特有的,因为单词可以引用任何合理的字符串,包括空格。

在这种情况下,我知道标准错误消息1:参数未设置是不够的,所以我放大了我们在这里期望的值类型-路径名目录的。

哲学注释:

shell不是面向对象的语言,所以消息说路径名,不是目录。在这个层次上,我宁愿保持简单-函数的参数只是字符串。

  • 这不仅仅是检查存在性:这是在用户级别检查可访问性。SO问题代表存在只有。所以正确的答案是测试-d正如@Grundlefleck解释的那样。 评论 2013年2月9日20:16
  • 8
    @F、。豪里-他没有要求更多,这是真的。然而,我发现我通常需要知道更多。 评论 2013年2月9日23:50
  • 我从来没有想过,任何测试都不可能是决定性的,除非它作为根运行。测试-d/不可读/存在将失败,即使参数存在。 评论 2016年4月2日17:32
42
如果[-d“$Directory”-a-w“$Directory“]然后#报表fi(菲涅耳)

上述代码检查目录是否存在以及是否可写。

1
  • 1
    -a实际上与-e相同。它已被“弃用”,不鼓励使用。 评论 2014年1月28日8:39
35

更多功能使用找到

  • 检查子目录中是否存在文件夹:

    find=`find-type d-name“myDirectory”`如果[-n“$found”]然后#变量“found”包含“myDirectory”所在的完整路径。#如果有多个名为“myDirectory”的文件夹,它可能包含多行。fi(菲涅耳)
  • 根据当前目录中的模式检查是否存在一个或多个文件夹:

    find=`find-maxdepth 1-type d-name“my*”`如果[-n“$found”]然后#变量“found”包含找到文件夹“my*”的完整路径。fi(菲涅耳)
  • 两种组合。在以下示例中,它检查当前目录中是否存在文件夹:

    find=`find-maxdepth 1-type d-name“myDirectory”`如果[-n“$found”]然后#变量'found'不为空=>“myDirectory”`存在。fi(菲涅耳)
2
  • 你好,尼尔。您的想法可能有助于根据以下模式检查目录是否存在:find-maxdepth 1-type d-name“pattern”你介意我在你的答案中加上这个技巧吗?干杯;)
    – oHo公司
    评论 2013年11月18日13:54
  • 喜欢这个。所有剩下的-d日建议您可以访问该目录,但如果我们只需要检查是否存在,那么这种查找方法很好。 评论 6月17日1:38
31
目录=/tmp如果[-d“$DIRECTORY”];然后echo“存在”fi(菲涅耳)

尝试联机

2
  • 记忆者空间之后[->[``-d.我因缺少空格而出错
    – 拉吉
    评论 2020年2月20日6:00
  • 4
    再一次,这个答案已经在2008年给出,并有更有用的解释。这里唯一的新鲜事物是网上游乐场。 评论 2020年3月5日13:16
23

实际上,您应该使用多种工具来获得防弹方法:

DIR_PATH=`readlink-f“${the_stuff_you_test}”`#删除符号链接并获取abs路径如果[[-d“${DIR_PATH}”]];然后#现在你正在测试echo“这是一个目录”;fi(菲涅耳)

只要使用空格和特殊字符,就无需担心"${}".

请注意[[]]不像[],但由于大多数人都使用现代版本的Bash(毕竟,大多数人甚至不使用命令行:-p),因此好处大于麻烦。

22

你是否考虑过在如果而不是三思而后行?

也就是说,如果您想在输入目录之前检查目录是否存在,请尝试这样做:

如果是pushd/path/you/want/to/enter;然后#要在此目录中运行的命令邻苯二胺fi(菲涅耳)

如果你选择的道路推送的存在,您将输入它,它将以退出0,这意味着然后语句的一部分将执行。如果它不存在,什么也不会发生(除了一些输出表明目录不存在,这可能对调试来说是一个有用的副作用)。

这似乎比这更好,这需要你重复:

如果[-d/path/you/want/to/enter];然后pushd/path/you/want/to/enter#要在此目录中运行的命令邻苯二胺fi(菲涅耳)

同样的东西也适用于光盘,毫伏,rm(毫米)等……如果您在不存在的文件上尝试它们,它们将退出并显示一条消息,表明它不存在然后块将被跳过。如果在确实存在的文件上尝试它们,则命令将执行并退出,状态为0,允许您然后要执行的块。

1
  • 2
    对我来说,pushd是最优雅的方式。我正要把它作为答案发布:) 评论 2017年12月7日17:10
20
[[-d“$DIR”&&!-L“$DIR”]]&&echo“这是一个目录,而不是符号链接”

注:引用变量是一种很好的做法。

说明:

  • -d日:检查它是否为目录
  • -L(左):检查它是否是符号链接
2
  • 解释一下就可以了(通过编辑您的答案,而不是在评论中)。 评论 2020年5月7日12:14
  • 如果您使用Bash的[[...]]一个例外是的RHS=,例如。[[$VAR=“$VAR”]](这是由于Bash将RHS解释为一个glob。) 评论 2022年7月8日16:27
17

检查目录是否存在,否则创建一个:

[-d“$DIRECTORY”]||mkdir$目录
2
  • 21
    你可以使用mkdir-p“$目录”达到同样的效果。 评论 2016年7月24日21:12
  • 周围需要双引号$目录mkdir公司也是一部分。否则,分词可能会导致不良结果。例如:dir=“a b”;mkdir$目录将生成两个目录b条正在创建,而不是单个a b类目录。 评论 2021年2月22日3:55
16
[-d~/Desktop/TEMPORAL/]&&echo“DIRECTORY EXIST”||echo《目录不存在》
1
16

要检查多个目录,请使用以下代码:

如果[-d“$DIRECTORY1”]和[-d”$DIRECT“2”],则#要做的事情fi(菲涅耳)
1
  • 你怎么能检查它不存在? 评论 2017年4月3日7:04
15

使用-e(电子)check将检查文件,其中包括目录。

如果[-e${FILE_PATH_AND_NAME}]然后echo“文件或目录存在。”fi(菲涅耳)
0
12

这个答案包装为shell脚本

示例

$is_dir~$is目录/tmp$is_dir~/bin$mkdir“/tmp/test我”$is_dir“/tmp/test我”$is_dir/asdf/asdf#在另一个脚本中调用它的示例DIR=~/mydata如果[$(is_dir$dir)==“NO”]然后echo“文件夹不存在:$DIR”;出口;fi(菲涅耳)

是(_D)

函数show_help(){IT=$(CAT<<EOF用法:DIR输出:是或否,取决于目录是否存在。)echo“$IT”出口}if[“$1”==“help”]然后显示帮助(_H)fi(菲涅耳)如果[-z“$1”]然后显示帮助(_H)fi(菲涅耳)DIR=1美元如果[-d$DIR];然后echo“是”;出口;fi(菲涅耳)echo“NO”;
10

根据乔纳森的评论:

如果您想创建目录,但它还不存在,那么最简单的技术是使用mkdir-p这将创建目录以及路径上任何缺少的目录,如果目录已经存在,则不会失败,因此您可以使用以下命令一次性完成所有操作:

mkdir-p/some/directory/you/want/to/exist||退出1
10

一个衬垫:

[[-d$Directory]]&&echo true
1
  • 为什么加倍[[而不是单身?
    – 草率的
    评论 5月30日12:47
9
如果[-d“$DIRECTORY”];然后#如果$DIRECTORY存在,将在此处输入fi(菲涅耳)

这并不完全正确。。。

如果要转到该目录,还需要具有该目录的执行权限。也许你也需要有写作权。

因此:

如果[-d“$DIRECTORY”]&&[-x“$DIRE”];然后# ... 转到该目录(即使directory是链接)cd$目录密码fi(菲涅耳)

如果[-d“$DIRECTORY”]&&[-w“$DIRE”];然后# ... 转到该目录并在其中写入内容(即使directory是一个链接)cd$目录触摸foobarfi(菲涅耳)
0
9

在某种程度上三元的形式,

[-d“$directory”]&&echo“exist”||echo”不存在“

而且有测试:

test-d“$directory”&&echo“exist”|echo”不存在
8
file=“foo”如果[[-e“$file”]];然后echo“File Exists”;fi;
1
8

这个最小二乘法命令与-我(长列表)选项返回有关文件和目录的属性信息。
尤其是第一个字符ls-升输出通常是d日或a-(破折号)。如果是d日所列的是一个目录。

下面一行中的命令将告诉您国际战略研究所变量是否包含目录路径:

[[$(ls-ld“$ISDIR”|剪切-c1)=='d']]&&echo“是,$ISDIR是一个目录。”||echo“抱歉,$ISDIR不是目录”

实际使用:

[克劳迪奥无处可去~]$ISDIR=“$HOME/音乐”[克劳迪奥无处可去~]$ls-ld“$ISDIR”drwxr-xr-x.2克劳迪奥·克劳迪奥4096 Aug 23 00:02/home/claudio/音乐[克劳迪奥无处可去~]$[[$(ls-ld“$ISDIR”|剪切-c1)=='d']]&&echo“是的,$ISDIR是一个目录。”||echo“抱歉,$ISDIR不是目录”是的,/home/claudio/Music是一个目录。[克劳迪奥无处可去~]$touch“空文件.txt”[克劳迪奥无处可去~]$ISDIR=“$HOME/empty file.txt”[克劳迪奥无处可去~]$[[$(ls-ld“$ISDIR”|剪切-c1)=='d']]&&echo“是,$ISDIR是一个目录。”||echo“抱歉,$ISDIR不是目录”对不起,/home/claudio/empty file.txt不是目录
0
7

有很多很好的解决方案,但如果您不在正确的目录中,最终每个脚本都会失败。代码如下:

如果[-d“$LINK_OR_DIR”];然后如果[-L“$LINK_OR_DIR”];然后#这是一个符号链接!#此处显示特定于符号链接的命令rm“$LINK_OR_DIR”其他的#这是一个目录!#此处显示目录命令rmdir“$LINK_OR_DIR”fi(菲涅耳)fi(菲涅耳)

只有在执行时您所在的目录中有您要检查的子目录,才能成功执行。

我理解最初的问题是这样的:无论用户在文件系统中的位置如何,都要验证目录是否存在。因此,使用命令“find”可能会达到以下目的:

dir=“”echo“输入要搜索的目录名:”读取目录查找$HOME-名称$dir-类型d

这个解决方案很好,因为它允许使用通配符,这是搜索文件/目录时的一个有用功能。唯一的问题是,如果搜索到的目录不存在,“find”命令将不向打印任何内容标准输出(对我来说,这不是一个优雅的解决方案),尽管如此,它仍将零退出。也许有人可以改进这一点。

1
  • 13
    如果一个程序在我的整个硬盘中查找一个目录,而不是礼貌地在我当前的工作目录中查找或使用我给它的绝对路径,我会很生气。你的建议对于一个名为定位但对其他任何东西都不好。。。
    – 沙罗
    评论 2012年2月1日9:29
7

下面是找到可以使用,

找到-键入d-name目录名-prune打印
0
6

(1)

[-d Piyush_Drv1]&&echo“”存在“”||echo”不存在“”

(2)

[`find.-type d-name Piyush_Drv1-print|wc-l`-eq 1]&&echo存在||echo“不存在”

(3)

[[-d run_dir&&!-L run_dir]]&&echo Exists||echo“不存在”

如果使用上述方法之一发现问题:

使用最小二乘法命令;目录不存在的情况-显示错误消息

[[`ls-ld SAMPLE_DIR|grep^d|wc-l`-eq 1]]&&echo存在||不存在

-ksh:not:未找到[无此类文件或目录]

1
  • “上面”指的是什么?这个答案或之前的答案中的三个命令行?(请回复编辑您的答案,不是在评论中。提前谢谢。)。 评论 2020年5月7日12:18

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.