for 循环输出的管道防止局部变量修改

for 循环输出的管道防止局部变量修改

我正在尝试编写一个简单的 bash 函数,该函数接受多个文件和/或目录作为其参数。它应该:

  1. 完全限定文件名。
  2. 对它们进行排序。
  3. 删除重复项。
  4. 打印所有实际存在的东西。
  5. 返回不存在的文件的数量。

我有一个脚本几乎可以满足我的要求,但在排序方面却失败了。脚本的返回值目前是正确的,但输出不正确(未排序且重复)。如果我| sort -u按照指示取消注释该语句,则输出是正确的,但返回值始终为0

注意:欢迎使用更简单的解决方案来解决问题,但问题实际上是关于为什么我的代码中会出现这种情况。也就是说,为什么添加管道似乎会阻止脚本增加变量r

这是脚本:

function uniqfile
{
    local r=0 

    for arg in "$@"
    do  
        readlink -e "$arg" || (( ++r ))

    done #| sort -u    ## remove that comment

    return $r
}

答案1

这是一个众所周知的 bash 陷阱,因为特征:

管道中的每个命令都作为单独的进程(即在子shell 中)执行。

这样修改后的变量对于子 shell 来说是本地的,并且一旦返回到父 shell 中就不可见。

为了避免这种情况,请重新编写代码以避免管道,并进行进程替换:

 for arg in "$@"
    do  
        readlink -e "$arg" || (( ++r ))

    done > >(sort -u)

答案2

强制| sort -u前面的位(因此整个 for 循环)在子进程中运行(bash 需要一个“STDOUT”来重定向到sort“STDIN”。(互联网似乎对这种情况的思考kshbash处理略有不同......首先或最后管道序列中的命令被放入子 shell 中?)

该线程讨论了类似的问题,并在最后给出了一个巧妙的解决方案:http://ubuntuforums.org/showthread.php?t=312017

摘抄
    #!/bin/bash
    exec 3< <(du | sort -n)  

    n=0
    while read size dir; do
      [ $size -gt 1000 ] && ((n++))
    done <&3
    exec 3<&-

    echo "Found $n too big files"

相关内容