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

これはよく知られたバッシュトラップです。特徴:

パイプラインの各コマンドは、別々のプロセス(つまりサブシェルで)で実行されます。

これらの変更された変数は子シェルにローカルであり、親シェルに返されると表示されません。

これを避けるために、パイプを避け、プロセス置換を実行するようにコードを書き直してください。

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

    done > >(sort -u)

答え2

| sort -usort前のビット(したがって完全なforループ)が子プロセスで実行されるように強制します(bashでは「STDIN」にリダイレクトするには「STDOUT」が必要ですkshbash) )はパイプラインシーケンスで最初にサブシェルに入れるのか、それとも最後に入れるのでしょうか?)

このスレッドでは同様の問題を議論し、最後にきれいな解決策を提供します。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"

関連情報