我想知道如何在shell脚本中使用if
语句来检查多个目录是否存在。
例如,如果/tmp
包含子目录test1
,test2
,test3
,我想将它们移动到另一个目录。
我正在使用if [ -d /tmp/test* ]; then mv test* /pathOfNewDir
但它不适用于if
声明部分。
答案 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个论点)。[[ -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功能:
exists foo*
展开到所有匹配的文件/目录,并将其名称作为单独的参数传递到功能。foo*
包含允许更改此行为的配置项(shell选项bash
和failglob
) - 虽然默认情况下但它的作用是POSIX的强制要求在这种情况下。 (nullglob
,遗憾的是,如果没有匹配,会失败。)zsh
)以确定是否找到任何匹配就足够了:
$1
引用了一个实际的现有文件系统项(由$1
文件 - 测试运算符的退出代码表示),则暗示该模式确实匹配了某些内容(至少一个,可能还有更多项目。)-e
测试的退出代码 - 由于是函数中的 last 命令 - 隐式地充当了函数的退出代码。答案 3 :(得分:-1)
此方法使用ls
和grep
创建匹配目录列表,或者在没有找到此类目录时写入错误:
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
执行任务会对文件名产生一些限制。此方法不适用于包含换行符或通配符的文件名。