使用排除列表在bash中查找包含find的目录

时间:2011-11-15 16:18:09

标签: linux bash find printf

现在在你想到之前,“这已经完成了”请继续阅读。

与大多数尝试查找bash脚本的人一样,你最终会将脚本硬编码为单行命令,但最终会在接下来的几个月/几年内编辑这个东西,所以你最终希望第一次就做对了。

我现在正在编写一个小备份程序来备份目录并需要找到它们,而不是需要排除的Directorie列表。说起来容易做起来难。让我上台:

#!/bin/bash
BasePath="/home/adesso/baldar"
declare -a Iggy
Iggy=( "/cgi-bin" 
    "/tmp" 
    "/test" 
    "/html" 
    "/icons" )
IggySubdomains=$(printf ",%s" "${Iggy[@]}")
IggySubdomains=${IggySubdomains:1}
echo $IggySubdomains
exit 0

现在结束时你会得到 / cgi-bin,/ tmp,/ test,/ html,/ icons 这证明了这个概念是有效的,但现在为了进一步了解,我需要使用find来搜索 BasePath ,并且只搜索所有子目录的一个级别,并排除数组中的子目录列表。 ..

如果我手动输入,那就是:

find /var/www/* \( -path '*/cgi-bin' -o -path '*/tmp' -o -path '*/test' -o -path '*/html' -o -path '*/icons' \) -prune -type d

我是否应该想要循环到每个子目录并做同样的事情......我希望你明白我的观点。

所以我想做的事情似乎有可能,但我有一点问题, printf“,%s”不喜欢我使用所有这些find -path或-o选项。这是否意味着我必须再次使用eval?

我试图在这里使用bash的功能,而不是一些for循环。任何建设性的意见将不胜感激。

3 个答案:

答案 0 :(得分:5)

尝试类似

的内容
find /var/www/* \( -path "${Iggy[0]}" $(printf -- '-o -path "*%s" ' "${Iggy[@]:1}") \) -prune -type d

看看会发生什么。

编辑:在示例中为每条路径添加了前导*。

这是基于您的描述的完整解决方案。

#!/usr/bin/env bash
basepath="/home/adesso/baldar"
ignore=("/cgi-bin" "/tmp" "/test" "/html" "/icons")

find "${basepath}" -maxdepth 1 -not \( -path "*${ignore[0]}" $(printf -- '-o -path "*%s" ' "${ignore[@]:1}") \) -not -path "${basepath}" -type d

$ basepath的子目录,不包括$ ignore中列出的子目录,假设$ ignore中至少有两个(修复并不难)。

答案 1 :(得分:2)

当给定包含文字空格的目录名时,现有答案是错误的。安全可靠的做法是使用循环。如果你关心的是利用“bash的力量” - 我认为一个强大的解决方案比一个有缺陷的解决方案更强大。 :)

BasePath="/home/adesso/baldar"
declare -a Iggy=( "/cgi-bin" "/tmp" "/test" "/html" "/icons" )

find_cmd=( find "$BasePath" '(' )

## This is the conventional approach:
# for x in "${Iggy[@]}"; do
#  find_cmd+=( -path "*${x}" -o )
#done

## This is the unconventional, only-barely-safe approach
## ...used only to avoid looping:
printf -v find_cmd_str ' -path "*"%q -o ' "${Iggy[@]}"
find_cmd_str=${find_cmd_str%" -o "}
eval "find_cmd+=( $find_cmd_str )"

find_cmd=( "${find_cmd[@]:0:${#find_cmd[@]} - 1}"

# and add the suffix
find_cmd+=( ')' -prune -type d )

# ...finally, to run the command:
"${find_cmd[@]}"

答案 2 :(得分:0)

FIND="$(which find --skip-alias)"
BasePath="/home/adesso/baldar"
Iggy=( "/cgi-bin" 
    "/tmp" 
    "/test" 
    "/html" 
    "/icons" )
SubDomains=( $(${FIND} ${BasePath}/* -maxdepth 0 -not \( -path "*${Iggy[0]}" $(printf -- '-o -path "*%s" ' "${Iggy[@]:1}") \) -type d) )
echo ${SubDomains[1]}

感谢@Sorpigal我有一个解决方案。我最终嵌套了命令替换,因此我可以在cron中使用该脚本,最后在所有部分中添加了Array定义。已知问题是名称中包含空格的目录。然而这已经解决了,所以试着保持简单,我认为这回答了我的问题。