Bash
處理單個文件作為整個管道的輸入和輸出
晚上好,
我想用一些管道命令過濾文件的內容,然後將結果寫回同一個文件。我知道,我不能按照我寫的方式那樣做。堅持,稍等 …
這是我擁有的一段 bash 腳本。
grep '^[a-zA-Z.:]' "$filepath" \ | sed -r '/^(rm|cd)/d' \ | uniq -u \ > "$filepath"
所以我認為我可以成功,而是使用流程替換。然後我寫道:
grep '^[a-zA-Z.:]' < <(cat "$filepath") | …
這也沒有解決任何問題。我希望程序替換能夠在某處“保存”我的輸入文件內容,例如在臨時文件中。它接縫我也不了解過程替換。
我閱讀了有關“就地”版本的主題,但這些文章強調了一些二進製文件的特殊選項,例如
sed -i
orsort -o
但我需要一個通用解決方案(我的意思是它必須適合任何管道命令)。那麼首先,為什麼“管道標準方式”不能做到這一點,下面發生了什麼?
:/
我應該如何解決我的問題?有人可以解釋一下這是怎麼一回事嗎?謝謝你。
如前所述,moreutils的海綿很棒。我使用這個腳本來模擬以避免 moreutils 依賴:
#!/bin/sh -e #Soak up input and tee it to arguments st=0; tmpf= tmpf="`mktemp`" && exec 3<>"$tmpf" || st="$?" rm -f "$tmpf" #remove it even if exec failed; noop if mktemp failed [ "$st" = 0 ] || exit "$st" cat >&3 </dev/fd/3 tee "$@" >/dev/null
你可以像這樣使用它:
grep '^[a-zA-Z.:]' "$filepath" \ | sed -r '/^(rm|cd)/d' \ | uniq -u | sponge "$filepath"
您不能使用簡單的輸出重定向來執行此操作,因為重定向發生在命令啟動之前,並且輸出重定向會截斷輸出文件。
換句話說,當 grep(管道的第一個簡單命令)啟動時,最後一次重定向已經截斷了輸入/輸出文件。
據我所知,實際上並沒有任何標準的 UNIX 實用程序可以進行真正的就地編輯。
sed -i
僅使用臨時文件模擬它。我猜原因是如果管道步驟失敗,真正的就地過濾很容易損壞文件。至於下面發生的事情——兩者都
|
使用<()
系統管道,它們一次通過 IO 一個緩衝區。該機制不會創建臨時文件(無論如何都不是真實的(文件系統)文件),它會嘗試避免一次將整個輸入保存在記憶體中。