如何仅在目录不存在时创建mkdir?

2861

我正在编写一个可在AIX上的KornShell(ksh)下运行的shell脚本。我想使用mkdir命令来创建目录。但是,如果该目录已经存在,则我不想执行任何操作。因此,我要么测试该目录是否不存在,要么抑制mkdir尝试创建现有目录时引发的“文件已存在”错误。

我应该如何最好地做到这一点?

17个回答

4644
尝试使用 mkdir -p 命令:
mkdir -p foo

请注意,这也将创建任何不存在的中间目录;例如,
mkdir -p foo/bar/baz

如果目录不存在,将创建目录foofoo/barfoo/bar/baz

一些实现(如GNU mkdir)将mkdir --parents作为更可读的别名,但这在POSIX / Single Unix规范中没有指定,并且在许多常见平台上不可用,例如macOS,各种BSD和各种商业Unix,因此应避免使用。

如果您希望在父目录不存在时出现错误,并且希望在目录不存在时创建该目录,则可以先test该目录是否存在:

[ -d foo ] || mkdir foo

15
你所使用的缩写示例正是不应该做的。这样做虽然可以节省编码空间,但却颠倒了逻辑。正确的方法应该使用"!"和"&&",这样更容易理解。 - Mike Q
26
这个问题是关于Unix类系统上的mkdir命令,而不是Windows上的。为了符合POSIX/Single Unix规范,使用-p选项是必须的,因此任何打算遵守这些规范的系统都将支持-p选项。对于Windows系统来说完全不同,除非你使用像Cygwin或MSYS这样的POSIX仿真层。 - Brian Campbell
51
今天我发现了一个关于 mkdir -p 的有趣事情,你可以使用花括号 {} 在命令中创建“复杂”的目录树。具体内容请见这里:http://technosophos.com/2010/04/15/mkdir-creating-multiple-subdirectories-one-command.html。 - herve
17
@MikeQ,我更希望使用 || 而不是 &&,因为这样整行命令的退出状态才正确。如果你的shell运行时开启了 errexit 或该命令是函数、switch-case等结构的最后一行时,这一点非常重要。 - rudimeier
11
这与mkdir无关,shell将这样的表达式扩展为一系列离散的参数,然后传递给mkdir - chepner
显示剩余8条评论

256

这应该可以工作:

$ mkdir -p dir

或者:

if [[ ! -e $dir ]]; then
    mkdir $dir
elif [[ ! -d $dir ]]; then
    echo "$dir already exists but is not a directory" 1>&2
fi

如果目录不存在,则创建该目录,但是如果您要创建的目录名称已被其他非目录内容使用,则会发出警告。


我认为Korn中没有-d操作符,而是使用-e来检查文件/目录的存在性。另外,它们都在成功时返回0,因此!是多余的。如果我错了请纠正我。 - alkar
1
据我所知,两个都是错误的。测试成功时返回“true”,而“-d”也存在(至少在MacOS X上)。 - Alnitak
7
值得一提的是,这并不完全是线程安全的。在您检查目录是否存在和尝试写入之间,事情可能会发生改变。 - Justin L.

115

使用 -p 标志。

man mkdir
mkdir -p foo

6
-p,--parents 如果需要,创建父级目录,已存在则不报错。 - Shankara Narayana

91

用一个命令定义复杂的目录树

mkdir -p project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}

只返回翻译后的文本:如果存在错误,请不要报错,必要时创建父目录 - Fedir RYKHTIK
27
请记住,这不是mkdir命令本身的特性,而是执行该命令的 shell 的特性。这被称为花括号扩展 - 据我所知,只有 Bash、ksh、zsh 和 C shell 支持它。 - Daniel Kamil Kozar
4
如果在逗号周围有空格,您可能会(一定)得到意外结果。请注意。 - Atlas7
1
@Atlas7指出,您需要转义通常是正则表达式的一部分的字符。(例如,您需要使用folder\ name而不是folder name - John Hamilton
4
这不是一个回答,而是一个独立的主题,更适合作为评论。 - Chris Page
“Defining”?你是指“创建”吗? - Peter Mortensen

54

如果您不想显示任何错误消息:

[ -d newdir ] || mkdir newdir

如果你想展示自己的错误信息:

[ -d newdir ] && echo "Directory Exists" || mkdir newdir

2
但是受竞态条件的影响呢? - Peter Mortensen
当然。如果您不想出现竞争条件,请使用mkdir -p。但是您将无法显示自己的“目录已存在”错误。 - Jahid

48

mkdir foo即使目录已经存在也能工作。为了只在名为“foo”的目录不存在时工作,请尝试使用-p标志。

示例:

mkdir -p foo

只有在目录"foo"不存在的情况下,才会创建该目录。 :)


3
正如 @BrianCampbell 所提到的,这也将在路径中创建任何其他目录。如果例如卷变为未挂载状态,则可能会在挂载点中创建目录,这可能是危险的。 - uliwitness

34
你可以使用一个 if 语句来检查目录是否存在。如果不存在,则创建该目录。
  1. dir=/home/dir_name

    if [ ! -d $dir ]
    then
         mkdir $dir
    else
         echo "目录已存在"
    fi
    
  2. 您可以使用mkdir命令的-p选项来创建目录。它将检查目录是否不存在,如果不存在则会创建。

    mkdir -p $dir
    

    mkdir -p还允许创建目录的树形结构。如果您想要使用同一命令创建父目录和子目录,则可以选择mkdir -p

    mkdir -p /home/parent_dir /home/parent_dir/child1 /home/parent_dir/child2
    

使用 if 循环有什么优势吗?为什么有人会选择它而不是 -p 选项?! - pedram bashiri
2
我已经与您分享了在文件夹不存在时创建文件夹的方法。这取决于个人需求。如果您有一个使用案例需要检查文件夹是否存在并想要跟踪它,那么可以选择解决方案1。如果无所谓是否存在,则可以选择解决方案2,它将在不存在时创建文件夹。 - AbhinavVaidya8

28

简单、无声并且致命:

mkdir -p /my/new/dir >/dev/null 2>&1

应该是:mkdir -p /my/new/dir >/dev/null 2>&1 - edoardesd
8
如果 my/new/dir 目录已经存在,使用命令 mkdir -p my/new/dir 不会报错,无需重定向输出。 - Leevi L
错别字已经修正。Leevi,我相信我遇到了一个需要压制输出的情况。 - moodboom
注意:对于不熟悉 Windows 的用户,即使文件夹存在,“-p” 仍然无法在 Windows 上运行。 - dube
如果权限不允许创建/parent/dir,mkdir -p /parent/dir 会报错吗?如果是这样的话,重定向可能被认为是“致命”的,或者至少是不明智的。 - WGroleau
当然,你是对的,事情总是会因为很多原因出错。如果你需要满足比OP请求更多的需求(权限、无效路径、空间不足等),你应该为它们编写脚本。 - moodboom

27

老而经典

mkdir /tmp/qq >/dev/null 2>&1

这个解决方案可以按照您的要求执行,而且没有其他解决方案中存在的竞态条件。

有时候最简单(也可能最丑陋)的解决方案是最好的。


6
如果 "tmp" 不存在,此操作将失败,并且不会给你任何确认信息。 - Mike Q
竞态条件?您能详细说明一下吗?非原子测试和创建? - Peter Mortensen
3
@Peter,像 [ -d newdir ] || mkdir newdir 这样的片段,当目录最初不存在时,存在竞争条件。因为在检查存在性和尝试创建之间,另一个进程可能会抢先创建该目录。因此,mkdir 将失败。 - paxdiablo
1
@Mike Q:在示例中选择基本路径“/tmp”可能是为了表示始终存在且对当前用户可写入的基本路径,例如用户具有足够的权限创建目录。您提出了一个有效的观点:逻辑有些矛盾,因为当此命令失败时,可能意味着两件事情:1)目录已存在或2)目录无法创建。这对于操作本身来说并不正确,因此对目录路径进行简单的后检查可以提供确认,或者下一个操作命令可以执行。 - hakre
mkdir -p /tmp/qq > /dev/null 2>&1 如果不存在,将创建 /tmp/。 - Jesse Nickles

18

在 Windows 8+ 系统上,mkdir 不再支持 -p 开关。

你可以使用以下命令:

IF NOT EXIST dir_name MKDIR dir_name

15
OP提到了AIX kornshell,与Windows无关,对吗? - J. Chomel
1
你确定之前它被支持过吗?你有来源吗? - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接