如果存在多个目录,则移动目录 - 测试一个globbing模式是否匹配任何内容

时间:2015-03-03 20:51:56

标签: linux bash shell glob

我想知道如何在shell脚本中使用if语句来检查多个目录是否存在。

例如,如果/tmp包含子目录test1test2test3,我想将它们移动到另一个目录。

我正在使用if [ -d /tmp/test* ]; then mv test* /pathOfNewDir 但它不适用于if声明部分。

4 个答案:

答案 0 :(得分:1)

-d测试只接受一个参数,因此您需要单独测试每个目录。我也不建议移动测试*,因为它可能比你想要的更多。

使用双括号语法测试语法(例如if [[ -d ...),这是特定于bash的,但往往比单括号语法更清晰,更少陷阱。如果您只需要检查几个目录,可以使用if [[ -d /tmp/test1 && -d /tmp/test2 && -d /tmp/test3 ]]; then ...

这样的简单语句来完成

答案 1 :(得分:0)

您可能希望使用find

find /tmp -name "test*" -maxdepth 1 -type d -exec mv \{\} /target/directory \;

这会在test*下直接查找所有/tmp目录而不进行递归,并将其移至/target/directory

答案 2 :(得分:0)

不幸的是, shell的文件测试运算符(例如-d-f)仅在单个,文字路径上运行:< / p>

  • [ -d /tmp/test* ]等条件不起作用,因为如果/tmp/test*扩展为多个匹配,则会出现语法错误 (只接受了1个论点)。
  • bash变体[[ -d /tmp/test* ]]也不起作用,因为在[[ ... ]]内没有执行全局(路径名扩展)。

测试通配模式是否匹配任何 最干净的方法是定义辅助功能(此解决方案符合POSIX标准) :

exists() { [ -e "$1" ]; }

使用[unquoted]模式调用它,例如:

exists foo* && echo 'HAVE MATCHES'

# or, in an `if` statement:
if exists foo*; then # ...

唯一需要注意的是,如果{b}中有shopt -s failglob生效,如果没有匹配则会向stderr打印错误消息,并且不会执行其余命令。

有关该功能的说明,请参见下文。


应用于您的具体方案,我们得到(使用bash语法):

# Define aux. function
exists() { [[ -e $1 ]]; }

exists /tmp/test*/ && mv /tmp/test*/ /path/to/new/dir
  • 请注意/中的结尾/tmp/test*/,以确保只有目录匹配,如果有的话。

  • &&确保仅在函数的退出代码为true时才执行以下命令。

  • mv /tmp/test*/ ...一次将所有匹配的目录移动到新的目标目录。


或者,捕获globbing会生成辅助数组变量:

if matches=(/tmp/test*/) && [[ -e ${matches[0]} ]]; then
  mv "${matches[@]}" /path/to/new/dir
fi

或者,单独处理匹配:

for d in /tmp/test*/; do
   [[ -e $d ]] || break # exit, if no actual match
   # Process individual match.
   mv "$d" /path/to/new/dir
done

辅助函数exists() { [ -e "$1" ]; }

解释

它利用了几个shell功能:

  • 如果使用[{1}}等[n unquoted]模式调用它,shell会将exists foo*展开到所有匹配的文件/目录,并将其名称​​作为单独的参数传递到功能。
  • 如果没有匹配,则模式将传递给函数 - 此行为由POSIX强制执行。
    • 警告:foo*包含允许更改此行为的配置项(shell选项bashfailglob) - 虽然默认情况下但它的作用是POSIX的强制要求在这种情况下。 (nullglob,遗憾的是,如果没有匹配,会失败。)
  • 在函数内部,检查 1st 参数(zsh)以确定是否找到任何匹配就足够了:
    • 如果第一个参数$1引用了一个实际的现有文件系统项(由$1文件 - 测试运算符的退出代码表示),则暗示该模式确实匹配了某些内容(至少一个,可能还有更多项目。)
    • 否则,暗示模式是传递,暗示找到 no 匹配。
    • 请注意,-e测试的退出代码 - 由于是函数中的 last 命令 - 隐式地充当了函数的退出代码。

答案 3 :(得分:-1)

此方法使用lsgrep创建匹配目录列表,或者在没有找到此类目录时写入错误:

IFS="
" # input is separated with newlines
if dirs=$( ls -1 -F | grep "^test.*/" | tr -d "/" )
then
  # directories found - move them:
  for d in $dirs
  do
    mv "$d" "$target_directory"/
  done
else
  # no directories found - send error
fi

虽然将find用于此类任务似乎是可行的,但find并未根据评论直接提供OP所要求的匹配数量的反馈。

注意:使用ls执行任务会对文件名产生一些限制。此方法不适用于包含换行符或通配符的文件名。