BASH脚本继续通过EXIT命令

时间:2019-11-22 00:30:37

标签: bash

这是一个更大的bash(Fedora 30)脚本的一部分示例,该脚本显示了我遇到的问题

该脚本应该遍历目录树并在发现任何文件名超过103个字符时退出。

SS_NORMAL=0
JOLIET_MAX=103
MD5FILE=/tmp/blah.md5

function myExit
{
    echo Exiting $1 ...
    exit
}

function traverse
{
    find . -type f -print0 | 
       while IFS= read -r -d '' MD5_FILESPEC; do
          MD5_BASE=$(basename "$MD5_FILESPEC")
          if [ "${#MD5_BASE}" -gt "$JOLIET_MAX" ]; then
              myExit "[FAIL] Filename size ${#MD5_BASE} too long - $MD5_FILESPEC"
           fi
       done
}

traverse
date; date; date

它可以正常工作,直到找到那些长文件名之一。它调用myExit并退出循环,但并非一直退出脚本。我总是在输出的末尾看到这三个日期,我应该不会。

我该如何处理?

2 个答案:

答案 0 :(得分:3)

解决while循环在子进程中运行的问题的一种简单方法是进行逆转:让while在同一shell中运行,这是一个子进程来生成文件

但是,如果来自find的文件名的接收者必须位于|运算符的右边,我们该怎么做?答案是,在GNU Bash中,我们有一个语言扩展名为“进程替换”。

进程替换是Bash转换为看起来像文件名的字符串的一种语法,并被命令以这种方式接受。程序打开并读取该文件(或从另一个方向写入文件)时,它将通过管道与另一个进程进行通信。

想法的构想:

   while IFS= read -r -d '' MD5_FILESPEC; do
      MD5_BASE=$(basename "$MD5_FILESPEC")
      if [ "${#MD5_BASE}" -gt "$JOLIET_MAX" ]; then
          myExit "[FAIL] Filename size ${#MD5_BASE} too long - $MD5_FILESPEC"
       fi
   done < <(find . -type f -print0)
   #      ^^^^^^^^^^^^^^^^^^^^^^^^^ this is the process substitution

答案 1 :(得分:1)

如@KamilCuk所述,循环中从findread的管道意味着exit出现在子外壳中。也就是说,当您拥有find . -type f -print0 | <do some stuff>,并且<do some stuff>包含对exit的调用时,exit适用于|创建的子外壳中。对于您的脚本,myExit正在调用exit,它结束了管道右侧的while循环,但这并未结束{{1 }}实际上正在运行。 traverse然后结束,traverse被执行3次,脚本结束。

最简单的选择可能是在脚本顶部使用date。这是一种扭曲的方法:如果任何返回非零值,脚本将退出。

为此,将整个set -e函数替换为:

myExit

现在,从循环内部调用该函数时,您将获得一个非零的返回码,并且脚本应立即退出。

一种更宽容的方法是如上所述更改set -e function myExit() { echo "Exiting $1 ..." return 1 } ,但不添加myExit1,并在对{{1 }}:

set -e

然后将对return 1的呼叫更改为此:

myExit

现在,当if [ "${#MD5_BASE}" -gt "$JOLIET_MAX" ]; then myExit "[FAIL] Filename size ${#MD5_BASE} too long - $MD5_FILESPEC" return 1 fi 块触发时,它将调用traverse,后者调用if ! traverse; then exit; fi ,终止子外壳,此时if返回值{ {1}},条件myExit的计算结果为exit,并调用traverse

您的问题的另一个答案建议使用流程替换,这也是一个很好的解决方案。这显示了用于这种类型的循环操作的更典型的模式:

1

最后,关于样式偏好,我可能会放弃if作为一个单独的函数,除非您有计划对其进行扩展。照原样,似乎只是造成了不必要的复杂性。

相关问题