使用 rm 清除多个目录

使用 rm 清除多个目录

我正在尝试清除存储在数组中的多个目录。这是一个简化的示例(我有更多目录)。

#!/bin/bash    

$IMAGES_DIR="/Users/michael/scripts/imagefiles"
$BACKUP_DIR="/Users/michael/scripts/imagebackups"

...

array=( $IMAGES_DIR $BACKUP_DIR )
for i in ${array[@]}
do
    if [ "$(ls -A $i)" ]; then     # check that directory has files in it
        rm "$i/"*                  # remove them 
    fi
done

我收到每个目录的错误,例如:

rm: /Users/michael/scripts/imagefiles/*: 没有这样的文件或目录

答案1

用一个命令来完成这一切怎么样?

您可以通过一次调用捕获文件存在检查、通配和删除find。对于 GNU 版本,find我们有这样的:

for f in "${array[@]}"; do
     find "$f" -type f -delete
done

如果您没有 GNU,find请使用此调用:

find "$f" -type f -exec rm -f {} +

(如果您不想从整个目录层次结构中清除文件,而只想清除直接子文件,则-maxdepth 1在之前添加-type f添加。)

但等一下,还有更多……

作为John1024 明智地指出您可以通过将数组作为第一个参数传递给以下命令来完全放弃循环find

     find "${array[@]}" -type f -delete

那是因为:1) find将接受在一次执行中搜索和处理多个目录2)shell 将分割数组,使每个元素(目录)成为 的单独位置参数find

答案2

将您的代码更改为:

#!/bin/bash    

IMAGES_DIR="/Users/michael/scripts/imagefiles"
BACKUP_DIR="/Users/michael/scripts/imagebackups"

array=( $IMAGES_DIR $BACKUP_DIR )
for i in "${array[@]}"
do
    if [ "$(ls -A "$i")" ]; then     
        rm "${i:?}"/*                 
    fi
done

错误:

  1. 放置$在变量赋值的左侧
  2. 不引用$iinif [ "$(ls -A $i)" ];then
  3. 用于"${var:?}"确保这一点,rm "$i/"*永远不会扩展到/*

答案3

如果文件操作数不存在,则选项使实用程序不会抱怨-frm它也不会因失败而退出。

什么是可能在您的情况下发生的情况是,除了具有隐藏名称的文件或目录之外,一个或多个目录是空的,因此*模式末尾的 不会扩展到任何内容。您可以通过设置shell 选项*使 glob 匹配隐藏的名称。bashdotglob

您也不应该$在赋值中使用变量名,并且需要双引号变量扩展以避免分词和文件名生成(通配符)。变量名应该小写,这样就不会无意中破坏环境变量或特殊的 shell 变量。

考虑这些因素的代码的替代表述;

#!/bin/bash    

shopt -s dotglob

images_dir="/Users/michael/scripts/imagefiles"
backup_dir="/Users/michael/scripts/imagebackups"

dirs=( "$images_dir" "$backup_dir" )

for dir in "${dirs[@]}"; do
    rm -f "$dir"/*
done

上面的代码将尝试从目录中删除所有文件。如果目录有子目录,您将收到与rm此相关的错误。您是否也想删除这些,请使用-rwith rm

答案4

rm如果您的目标是删除文件夹数组中的所有文件,另一种选择是像这样传入数组:

#!/bin/bash    

$IMAGES_DIR="/Users/michael/scripts/imagefiles"
$BACKUP_DIR="/Users/michael/scripts/imagebackups"

# ...

# to preserve whitespaces in path strings, add double quotes around each variable
array=( "$IMAGES_DIR" "$BACKUP_DIR" )

# this appends "/*" to the end of each dirname if you want to delete the contents of the directories
# without deleting the directories themselves
array=( "${array[@]/%//*}" )

# this will spread the array into multiple calls to rm
rm -rf ${array[@]}

单行示例:

rm -rf ${array[@]/%//*}

但如果你也想删除文件夹,你可以使用

rm -rf ${array[@]}

需要注意的一个区别B层的解决方案,是 whilefind会打印查找提供的路径时出现的任何错误,rm但在本例中不会。

编辑:

作为善行指出,重要的是要注意,如果路径中存在空格或 shell 通配符,则像这样扩展数组可能会很危险。为了避免这些字符分割数组,请确保在添加到数组的变量两边添加双引号。

相关内容