Bash 如何在find的-exec中获取basename?

Bash 如何在find的-exec中获取basename?,bash,rm,Bash,Rm,我无法使以下脚本(属于较大备份脚本的一部分)正常工作: BACKUPDIR=/BACKUP/db01/physical/incremental # Backups base directory FULLBACKUPDIR=$BACKUPDIR/full # Full backups directory INCRBACKUPDIR=$BACKUPDIR/incr # Incremental backups directory KEEP=5 # Number of full backups (and

我无法使以下脚本(属于较大备份脚本的一部分)正常工作:

BACKUPDIR=/BACKUP/db01/physical/incremental # Backups base directory
FULLBACKUPDIR=$BACKUPDIR/full # Full backups directory
INCRBACKUPDIR=$BACKUPDIR/incr # Incremental backups directory
KEEP=5 # Number of full backups (and its incrementals) to keep
...
FIRST_DELETE=`expr $KEEP + 1` # add one to the number of backups to keep, this will be the first deleted
FILE0=`ls -ltr $FULLBACKUPDIR | awk '{print $9}' | tail -$FIRST_DELETE | head -1` # search for the first backup to be deleted
...
find $FULLBACKUPDIR -maxdepth 1 -type d ! -newer $FULLBACKUPDIR/$FILE0 -execdir echo "removing: "$FULLBACKUPDIR/$(basename {}) \; -execdir bash -c 'rm -rf $FULLBACKUPDIR/$(basename {})' \; -execdir echo "removing: "$INCRBACKUPDIR/$(basename {}) \; -execdir bash -c 'rm -rf $INCRBACKUPDIR/$(basename {})' \;
因此,find可以正常工作,它自己会输出如下内容:

/BACKUPS/db01/physical/incremental/full/2013-08-12_17-51-28
/BACKUPS/db01/physical/incremental/full/2013-08-12_17-51-28
/BACKUPS/db01/physical/incremental/full/2013-08-12_17-25-07
我想要的是-exec回显一行,显示要删除的内容,然后从两个目录中删除文件夹

我尝试了各种方法来获得基本名称,但似乎没有任何效果。我明白了:

removing: /BACKUPS/mysql/physical/incremental/full/"/BACKUPS/mysql/physical/incremental/full/2013-08-12_17-51-28"
removing: /BACKUPS/mysql/physical/incremental/incr/"/BACKUPS/mysql/physical/incremental/full/2013-08-12_17-51-28"
removing: /BACKUPS/mysql/physical/incremental/full/"/BACKUPS/mysql/physical/incremental/full/2013-08-12_17-25-07"
当然,文件夹不会因为不存在而被删除,只会因为-f选项而自动失败。如果删除-f,则会在每个rm上出现“找不到”错误

我如何做到这一点?因为备份和部分备份可能存储在不同的存储系统中,所以我确实需要能够获取文件夹名称,以便在任何已知路径中使用

首先运行
$(basename{})
,将
删除:$INCRBACKUPDIR/$(basename{})
更改为
删除:$INCRBACKUPDIR/{}
,然后替换
{}

绕过它的一种方法可能是通过管道将其传输到bash:

-exec echo "echo \"removing: \\\"$INCRBACKUPDIR/\$(basename {})\\\"\" | bash" \;
这里有很多破房子

  • 所有caps变量都是按约定的env变量,不应在脚本中使用
  • 使用旧的反勾号而不是
    $()
  • 解析
    ls
    (!)的输出
  • 解析
    ls-l的输出(!!!)
  • 展开已知包含不带全引号的路径的变量
为了改善这一点,您完全需要正确地执行bash,例如

-execdir bash -c 'filepath="$1" ; base=$(basename "$filepath") ; echo use $filepath and $base here' -- {} \;
但是,这个怎么样:

#!/usr/bin/env bash

backup_base=/BACKUP/db01/physical/incremental
full_backup="$backup_base"/full
incremental_backup="$backup_base"/incr
keep=5
rm=echo

let n=0
while IFS= read -r -d $'\0' line ; do
    file="${line#* }"
    if [[ $n -lt $keep ]] ; then
            let n=n+1
            continue
    fi
    base=$(basename "$file")
    echo "removing: $full_backup/$base"
    "$rm" -rf -- "$full_backup"/"$base"
    echo "removing: $incremental_backup/$base"
    "$rm" -rf -- "$incremental_backup"/"$base"
done < <(find "$full_backup" -maxdepth 1 -printf '%T@.%p\0' 2>/dev/null | sort -z -r -n -t. -k1,2)
#/usr/bin/env bash
backup\u base=/backup/db01/physical/incremental
完全备份=“$backup\u base”/full
增量备份=“$backup\u base”/incr
保持=5
rm=回波
设n=0
而IFS=read-r-d$'\0'行;做
file=“${line#*}”
如果[$n-lt$keep]];然后
设n=n+1
持续
fi
base=$(basename“$文件”)
echo“删除:$full_backup/$base”
“$rm”-rf--“$full_backup”/“$base”
echo“删除:$incremental_backup/$base”
“$rm”-rf--“$incremental_backup”/“$base”
完成
在备份目录下的文件和目录上迭代,并跳过前5步。从与其余文件名匹配的完整和增量dirs文件中删除

这是一个本质上安全的版本,当然定时攻击除外


我已将
rm
定义为
echo
,以避免意外删除;一旦确定正确,将其调回
rm
进行实际删除。

为了节省时间,我选择了第一个解决方案,因为删除失败会在备份建立时导致存储问题<代码>查找$FULLBACKUPDIR-maxdepth 1-type d-较新的“$FULLBACKUPDIR/$FILE0”\-execdir bash-c'base=$(basename“$2”);echo“removing:$1/$base”--$FULLBACKUPDIR{}\\-execdir bash-c'base=$(basename“$2”);rm-rf$1/$base'-$FULLBACKUPDIR{}\\-execdir bash-c'base=$(basename“$2”);echo“removing:$1/$base”--$INCRBACKUPDIR{}\\-execdir bash-c'base=$(basename“$2”);rm-rf$1/$base'-$INCRBACKUPDIR{}\我肯定会回去研究更健壮的WHILE循环方法,并在有时间时更新脚本。感谢您让我走上正轨。实际上,-execdir方法是首选方法,因为它不会遭受符号链接攻击,从而允许本地用户以调用脚本的权限删除任意文件。有关find的安全问题,请参阅GNU文档。要执行的部分可以是单独的脚本