bash 中的转换问题

bash 中的转换问题

尝试使用 find 的包装器但遇到以下问题。例如,我希望提供一些目录作为参数,但最后一个参数始终是一个数字,指示应删除多旧的数据。例如:

rmoldfiles dir1 dir2 dir3 20

这应该会删除超过 30 天的旧文件looking at mtime of course

这是脚本:

#!/bin/bash

die()
{
  echo >&2 "$@"
  exit 1
}

usage()
{
  echo >&2 "Usage: $0 [dir1 dir2 dir3] [days old]"
  die
}

if [[ (($# < 1)) || -f "$1" ]]; then
  if [[ -f "$1" ]]; then 
    printf '%s\n' "Please provide a directory"
  fi
  usage
fi 

while (( $# )); do 
  while IFS= read -r -d $'\0' file; do
    printf 'rm %s\n' "$file" 
    sleep 1
  done < <(find "$1" -type f -mtime +$2 -print0)
  shift
done

echo "Done deleting"

问题

如何shift目录但不是最后一个参数。

答案1

几个解决方案。

  1. 选出最后一个命令行参数。

    args=( "$@" )
    num=${args[-1]}
    args=( "${args[@]:0:${#args[@]} - 1}" )
    

    (然后用于find "${args[@]}" -type f -mtime "+$num" -print -delete删除这些文件)。

  2. 先把号码放上去。

     num=$1; shift
    

    (然后用于find "$@" -type f -mtime "+$num" -print -delete删除文件)。

仅当您有数百或数千个目录需要处理时才需要循环,在这种情况下,find单次调用命令会太长。否则,不要循环。find可以采用多个搜索路径。

如果您想插入延迟并rm显式使用,并且为每个文件提供一些格式化输出:

find "$@" -type f -mtime "+$num" -exec sh -c '
    for pathname do
        printf "Removing %s\n" "$pathname"
        rm -- "$pathname"
        sleep 1
    done' sh {} +

如果你发现你需要循环遍历目录(或者如果这样感觉更好):

# Assumes that the arguments are in the order
#      num dir1 dir2 dir3 ...

num=$1
shift

for dir do
    printf 'Processing %s...\n' "$dir"

    find "$dir" -type f -mtime "+$num" -exec sh -c '
        for pathname do
            printf "Removing %s\n" "$pathname"
            rm -- "$pathname"
            sleep 1
        done' sh {} +
done

或者,

# Assumes that the arguments are in the order
#      dir1 dir2 dir3 ... num

args=( "$@" )
num=${args[-1]}
args=( "${args[@]:0:${#args[@]} - 1}" )

for dir in "${args[@]}"; do

    # as above

done

答案2

由于您只期望(并提供)年龄参数之前的三个目录,因此不要不加区别地循环;相反,显式循环:

for dir in 1 2 3; do
  # work with "$1"
  shift
done

或者当剩下一个参数时停止循环:

while [ "$#" -gt 1 ]; do
  echo "Work with $1"
  shift;
done

由于“days”参数在每个班次期间都会移动,因此您需要首先将其保存:

days=$4

...在调用循环之前。

...如果您允许传递任意数量的目录:

[ "$#" -gt 1 ] || exit 1
days=${@: -1}
while [ "$#" -gt 1 ]; do
  echo work with "$1" and "$days"
  shift
done

这使用 bash 数组$@并要求它的最后一个元素(由 表示-1,用空格分隔以防止它被解释为 的修饰符:);然后它逐个循环参数,直到剩下一个(最后的初始“day”参数)。

答案3

只需更改(( $# ))(( $# > 1))

while (( $# > 1 )); do
  echo "file is: $1"
done

echo "days are: $1"

相关内容