我正在编写一个shell脚本,它正在检查bin目录是否存在于/ home目录下的所有users目录下。 bin目录可以直接存在于用户目录下,也可以存在于用户目录的子目录下 我的意思是说我有一个用户作为/ home下的amit。所以bin目录可以直接作为/ amit / bin存在,也可以作为/ amit / jash / bin存在
现在我的要求是我应该有一个用户目录列表,其中bin目录不存在于用户目录下或用户目录的子目录下。我试过这个命令: 找/ home -type d! -exec test -e'{} / bin'\; -print 但它不起作用。但是,当我用某个文件替换bin目录时,该命令工作正常。看起来这个命令特别适用于文件。目录有没有类似的命令?任何有关这方面的帮助将不胜感激。
答案 0 :(得分:2)
你走在正确的轨道上。问题是你的测试“在这个目标中不存在以下目录”不能在find的条件下表达,只能返回顶级目录。所以你需要以这种或那种方式进行嵌套。
一种策略是在bash中使用for循环:
$ mkdir foo bar baz one two
$ mkdir bar/bin baz/bin
$ for d in /home/*/; do find "$d" -type d -name bin | grep -q . || echo "$d"; done
foo/
one/
two/
这使用路径名扩展(globbing)来生成要测试的目录列表,然后检查是否存在“bin”。如果该检查失败(即找不到输出),则打印该目录。请注意/home/*/
上的尾部斜杠,它确保您只在目录中搜索,而不是/home/
中可能意外存在的文件。
如果你不想依赖bash,另一种可能是使用嵌套的find
:
$ find /home/ -type d -depth 1 -not -exec sh -c "find {}/ -type d -name bin -print | grep -q . " \; -print
/home/foo
/home/one
/home/two
这大致重复了上面bash for
循环的效果,但是将find
嵌套在find -exec
中。它使用grep -q .
将find
的输出转换为退出状态,该状态可用作外部 find
的条件。
请注意,由于您正在寻找 bin目录,我们希望使用test -d
而不是test -e
(这也会检查bin 文件,这对你来说无关紧要。)
另一种选择是使用bash进程重定向。在多行上以便于阅读:
cd /home/
comm -3 \
<(printf '%s\n' */ | sed 's|/.*||' | sort) \
<(find */ -type d -name bin | cut -d/ -f1 | uniq)
这很遗憾地要求您在运行之前更改为/home
目录,因为它会删除子目录。如果你有这么倾向的话,你当然可以把它折叠成一个很长的单线。
此comm
解决方案还存在在名称中包含特殊字符的目录失败的风险,例如换行符。
最后一个选项是bash-only,但不仅仅是单行。它涉及从完整列表中减去包含“bin”的目录。它使用关联数组和globstar
,因此它依赖于bash版本4。
#!/usr/bin/env bash
shopt -s globstar
# Go to our root
cd /home
# Declare an associative array
declare -A dirs=()
# Populate the array with our "full" list of home directories
for d in */; do dirs[${d%/}]=""; done
# Remove directories that contain a "bin" somewhere inside 'em
for d in **/bin; do unset dirs[${d%%/*}]; done
# Print the result in reproducible form
declare -p dirs
# Or print the result just as a list of words.
printf '%s\n' "${!dirs[@]}"
请注意,我们将目录存储在数组 index 中,其中(1)使我们可以轻松查找和删除项目,以及(2)确保唯一条目,即使一个用户拥有他们家下面的多个“bin”目录。
答案 1 :(得分:1)
cd /home
find . -maxdepth 1 -type d ! -name . | sort > a
find . -type d -name bin | cut -d/ -f1,2 | sort > b
comm -23 a b
在这里,我制作了两个排序列表。第一个包含所有主目录,第二个包含任何bin子目录的顶级父目录。最后,我输出第二个中没有的第一个列表中的任何项目。