Bash

循環輸出管道可防止局部變數修改

  • September 15, 2014

我正在嘗試編寫一個簡單的 bash 函式,該函式將多個文件和/或目錄作為其參數。這應該:

  1. 完全限定文件名。
  2. 對它們進行排序。
  3. 刪除重複項。
  4. 列印所有實際存在的內容。
  5. 返回不存在文件的數量。

我有一個幾乎可以完成我想要的腳本,但在排序上失敗了。腳本的返回值是正確的,但輸出不正確(未排序和重複)。如果我| sort -u按照指示取消註釋該語句,則輸出是正確的,但返回值始終為0.

NB 歡迎使用更簡單的解決方案來解決問題,但問題實際上是關於為什麼會在我的程式碼中發生這種情況。也就是說,為什麼添加管道似乎會阻止腳本增加變數r

這是腳本:

function uniqfile
{
   local r=0 

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

   done #| sort -u    ## remove that comment

   return $r
}

由於這個特性,這是一個眾所周知的 bash 陷阱:

管道中的每個命令都作為單獨的程序執行(即,在子shell 中)。

這樣修改後的變數對於子外殼來說是本地的,並且一旦回到父外殼中就不會可見。

為避免這種情況,請改寫您的程式碼以避免管道,並使用程序替換:

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

   done > >(sort -u)

強制前面的| 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"

引用自:https://unix.stackexchange.com/questions/21743