简体   繁体   English

如何测试Linux目录是否只包含一个子目录而没有其他文件?

[英]How to test if a Linux directory contain only one subdirectory and no other files?

In a /bin/sh script, I'd like to check whether a directory contains only one subdir and no other files (aside from "." and "..", of course). /bin/sh脚本中,我想检查目录是否只包含一个子目录而不包含其他文件(当然除了“。”和“..”)。 I could probably parse the output of ls , but I also understand that's generally a bad idea. 我可以解析ls的输出,但我也明白这通常是一个坏主意。 Suggestions? 建议?

Reason for questions: When I zip a folder on, say, a windows machine, and I unzip it under Linux, sometimes I get a directory whose contents are that of the original folder; 问题的原因:当我在Windows机器上zip文件夹,然后在Linux下解压缩它时,有时我会得到一个目录,其内容是原始文件夹的内容; sometimes I get a directory containing exactly one subdir, whose contents are that of the original folder. 有时我得到一个目录只包含一个子目录,其内容是原始文件夹的内容。 (I assume that there's something that varies in the way that I use zip under Windows, or that the various windows machines I use are configured slightly differently, or ...who knows?) Anhow, I'd like, on the Linux side, to handle both kinds of results in more or less the same way, hence this question. (我假设我在Windows下使用zip的方式有所不同,或者我使用的各种Windows机器配置略有不同,或者......谁知道?)总之,我想,在Linux端,以大致相同的方式处理这两种结果,因此这个问题。

For those thinking "What if your Windows-side folder really did contain just one subdir?", it happens that that's OK in this case, although I grant that it's a corner-case for the problem specification. 对于那些想“如果你的Windows端文件夹真的包含一个子目录怎么办?”,那么在这种情况下就可以了,尽管我认为这是问题规范的一个例子。

find would be a good tool for this. find这将是一个很好的工具。 It has some neat arguments: 它有一些巧妙的论点:

  • -maxdepth 1 so it does not search recursively -maxdepth 1因此不会递归搜索
  • -type d searching only for directories -type d仅搜索目录
  • -printf 1 to overcome the problem with weird filenames (print 1 instead of the file name) -printf 1克服了奇怪的文件名(打印1而不是文件名)的问题

The full command is then: 完整的命令是:

find DIRECTORY -maxdepth 1 -type d -printf 1

This will print one character for each directory plus the directory itself so you are looking for directories that prints two characters (find has a nice feature that ignores . and .. when searching). 这将为每个目录和目录本身打印一个字符,这样您就可以查找打印两个字符的目录(find有一个很好的功能,可以忽略...搜索时)。

Then, you want to check if there are no other (non-directory) files: 然后,您要检查是否没有其他(非目录)文件:

find DIRECTORY -maxdepth 1 ! -type d -printf 1

The full check will then be: 完整的检查将是:

if [ "$(find DIRECTORY -maxdepth 1 -type d -printf 1 | wc -m)" -eq 2 \
        -a "$(find DIRECTORY -maxdepth 1 ! -type d -printf 1 | wc -m)" -eq 0 ]; then
    # It has only one subdirectory and no other content
fi

Or, you can make it one command using -printf 's %y which prints file type ( d for directory): 或者,您可以使用-printf%y创建一个命令,它打印文件类型( d代表目录):

if [ "$(find DIRECTORY -maxdepth 1 -printf %y)" = "dd" ]; then
    # It has only one subdirectory and no other content
fi

Your biggest issue in /bin/sh will be invisible files, since a * doesn't catch then [by default]. /bin/sh最大的问题是隐形文件,因为*默认情况下不会捕获[默认情况下]。

This will do what you want, I think: 我想这会做你想做的事情:

#!/bin/bash
count_()
{
    echo $(( $# - 2 )) # -2 to remove . and ..
}
count()
{
    count_ * .*
}
ITEM_COUNT=$(count)

Of course you can adapt it to take a path as an argument if you wish. 当然,如果您愿意,您可以根据路径进行调整。

Example output: 示例输出:

bash-3.2$ count
3
bash-3.2$ ll
total 0
drwxr-xr-x   5 christopher  wheel  170 Mar 18  2014 .
drwxrwxrwx   6 root         wheel  204 Jul  5 12:28 ..
drwxr-xr-x  14 christopher  wheel  476 Mar 18  2014 .git
drwxr-xr-x   5 christopher  wheel  170 Mar 18  2014 bin
drwxr-xr-x   4 christopher  wheel  136 Mar 18  2014 pylib

Another example: 另一个例子:

sh-3.2$ count_()
> {
>     echo $(( $# - 2 )) # -2 to remove . and ..
> }
sh-3.2$ count()
> {
>     count_ * .*
> }
sh-3.2$ ITEM_COUNT=$(count)
sh-3.2$ echo ${ITEM_COUNT}
3

Sidenote: 边注:

You're right that different zip implementations handle things differently, but on Linux, many tools treat zip /path/to/folder and zip /path/to/folder/ differently (which is absurdly irritating) . 你是对的,不同的zip实现以不同的方式处理事情,但在Linux上,许多工具将zip /path/to/folderzip /path/to/folder/不同(这是荒谬的烦人) If you're working in a controlled environment, you might want to instead normalize how things get zipped. 如果您在受控环境中工作,则可能需要规范化压缩事件的方式。 However, if this is a user-facing thing, then that sucks. 但是,如果这是一个面向用户的事情,那就太糟糕了。

If you're not using bash as the invoking shell: 如果你没有使用bash作为调用shell:

countFiles.sh : countFiles.sh

#!/bin/bash
count_()
{
    echo $(( $# - 2 )) # -2 to remove . and ..
}
count_ * .*

scriptThatWantsTheCountOfFiles : scriptThatWantsTheCountOfFiles

#!/bin/tcsh
set count = `./countFiles.sh`

To avoid having to parse output yourself, you can use find . 为避免必须自己解析输出,可以使用find

if [[ `find . -type d | wc -l` -eq 2 && \
      `find . -type f | wc -l` -eq 0 ]]; then

  echo yes

else

  echo no

fi

If you want to avoid recursing into the directory, you can specify -maxdepth 1 . 如果要避免递归到目录中,可以指定-maxdepth 1

See man find for some of the other options. 请参阅man find以了解其他一些选项。

The number of links to the directory inode can help somewhat, but not solve completely the problem. 目录inode的链接数量可以有所帮助,但不能完全解决问题。 A directory has 2 + n links pointing to it, being n the number of subdirectories created inside. 一个目录有2 + n指向它的链接, n是在里面创建的子目录的数量。 So, if you try to find all the directories with only 3 links, you'll get the directories with only one subdirectory inside. 因此,如果您尝试查找只有3链接的所有目录,您将获得内部只有一个子目录的目录。 But the only solution to get a no files directory is to search it. 但获取无文件目录的唯一解决方案是搜索它。

Perhaps you can think in a mixed, two phase solution, in which first you find all the directories with 3 links pointing to them (very efficient). 也许你可以在混合的两阶段解决方案中思考,首先你会发现所有目录都有3指向它们的链接(非常有效)。 Then you read only those, finding for no plain files inside. 然后你只读那些,发现里面没有普通文件。

Here's a portable shell function, tested in Dash: 这是一个便携式shell函数,在Dash中测试过:

check() {
    d=
    for i in "$1"/* "$1"/.* 
    do
        test ddd != "$d" && test -d "$i" || return 1
        d=d$d
    done
    test ddd = "$d"
}

We use the variable d to count how many directories we've seen. 我们使用变量d来计算我们看到的目录数量。 We're expecting three ( . , .. and the target directory). 我们期待三个( ...和目标目录)。 If we've already seen three, then exit early; 如果我们已经看过三个,那就提前退出; similarly if we've seen a non-directory. 同样,如果我们看到一个非目录。

If we make it to the end of the loop, we check that we've seen three directories; 如果我们到循环结束,我们检查我们已经看到三个目录; the return value of test becomes the return value of the function. test的返回值成为函数的返回值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM