Bash 调用和数组

Bash 调用和数组

我是 bash 脚本编写的新手,尽管它仍然是初稿,但使该脚本按我的预期工作:

#!/bin/bash
find /var/www/site.com/ -type f -name "*.log" | xargs bash -c '
    
    for name; do

    parent=${name%/*}
    parent=${parent##*/}
    destdir=$(dirname $name)
    current_year=$(date +"%Y")

    if [[ "$name" =~ _([0-9]{4})- ]] &&
       [[ "$name" != *"$current_year"* ]]; then
         year="${BASH_REMATCH[1]}"
    else continue
    fi


    if [ ! -d "$destdir/$year/$parent" ]; then
         mkdir -p "$destdir/$year/"
    fi
          mv "$name" "$destdir/$year"

done '

find /var/www/site.com/ -type d -name "20*"  | xargs bash -c '

     for dir; do

     tar_name=$(echo $dir | grep -Eo '[0-9]{4}')
     tar cvfj '$tar_name'.tbz $dir 
done '
exit

如您所见,我在 bash 脚本中调用了 bash 两次。这是一个不好的做法吗?没有/没什么意义?或者我最好使用 find 命令的输出结果创建一个数组并迭代它?任何建议将不胜感激。提前致谢。 PS 抱歉缺少缩进

答案1

即使不查看内部 shell 脚本,也需要注意一些事项:

如果文件名包含空格、引号或反斜杠字符, Plainxargs将失败。它有自己的一套引用规则,与其他大多数规则不兼容。(我现在找不到参考问题。)

您缺少内联 shell 脚本的“zeroth”参数,这将导致第一个文件名被跳过。

此外,语法突出显示表明您的第二个命令已损坏,单引号关闭grep -Eo '[0-9]{4}'并重新打开整个脚本周围的引号。


现在,这个问题xargs很容易解决,find ... -print0 | xargs -0 command...许多实现(GNU、FreeBSD、Busybox)都支持这个问题。

要解决第零个参数的问题,您需要添加一个虚拟参数(以 结尾$0),例如

... | xargs -0 bash -c '...' sh

或者,您也可以使用find ... -exec bash -c '...' sh {} +.

但最好避免启动另一个 shell。在 Bash 中,你可以这样做:

find  ... -print0 | while IFS= read -r -d '' file; do
    something with "$file"
done

或者,

while IFS= read -r -d '' file; do
    something with "$file"
done < <(find ... -print0)

即使您需要在循环内设置变量并期望它们在循环外可用,后者也可以工作。

请参阅相关部分为什么循环查找的输出是不好的做法?(您没有使用命令替换,因此并非所有内容都是相关的。)

要将 的输出放入find数组中,请使用

mapfile -t -d '' array < <(find ... -print0)

答案2

假设您的 bash ≥4.3,您可以使用递归通配符而不是调用find.调用find并没有错(如果你做得对:见下文),但是当递归通配符起作用时,它就不那么方便了。你需要打电话shopt -s globstar启用递归通配符。

shopt -s globstar

for name in /var/www/site.com/**/*.log; do
done

for dir in /var/www/site.com/**/20*/; do
done

如果您确实使用find,切勿通过管道find输入xargs:它们使用不同的语法来分隔文件名,因此如果名称包含空格或\'".使用-exec调用 shell 或使用find … -print0 | xargs -0.看为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?了解更多信息。

相关内容