Pipe

是否有海綿的標準替代品將文件通過管道傳輸到自身?

  • February 18, 2020

我經常想做這樣的事情:

cat file | command > file

(這顯然不起作用)。我看到的唯一解決方案是sponge,即

cat file | command | sponge file

不幸的是,sponge我無法使用(我也無法安裝它或任何其他軟體包)。

有沒有更標準的快速方法來做到這一點,而不必每次都將其分解為多個命令(管道到臨時文件,管道返回原始文件,刪除臨時文件)?例如,我嘗試過tee,它似乎有效,但它是一致/安全的解決方案嗎?

一個shell函式替換sponge

mysponge () (
   append=false

   while getopts 'a' opt; do
       case $opt in
           a) append=true ;;
           *) echo error; exit 1
       esac
   done
   shift "$(( OPTIND - 1 ))"

   outfile=$1

   tmpfile=$(mktemp "$(dirname "$outfile")/tmp-sponge.XXXXXXXX") &&
   cat >"$tmpfile" &&
   if "$append"; then
       cat "$tmpfile" >>"$outfile"
   else
       if [ -f "$outfile" ]; then
           chmod --reference="$outfile" "$tmpfile"
       fi
       if [ -f "$outfile" ]; then
           mv "$tmpfile" "$outfile"
       elif [ -n "$outfile" ] && [ ! -e "$outfile" ]; then
           cat "$tmpfile" >"$outfile"
       else
           cat "$tmpfile"
       fi
   fi &&
   rm -f "$tmpfile"
)

這個myspongeshell 函式將標準輸入上的所有可用數據傳遞到一個臨時文件。

當所有數據都被重定向到臨時文件時,收集的數據被複製到函式參數命名的文件中。如果不將數據附加到文件中(即-a不使用),並且如果給定的輸出文件名引用現有的正常文件,如果它不存在,則使用mv(如果文件是現有的正常文件,首先嘗試使用 GNU 將文件模式轉移到臨時文件chmod)。如果輸出不是正常文件(命名管道、標準輸出等),則數據以cat.

如果命令行上沒有給出文件,則收集的數據將發送到標準輸出。

最後,臨時文件被刪除。

函式中的每一步都依賴於上一步的成功完成。如果一個命令失敗(它可能包含重要數據),則不會嘗試刪除臨時文件。

如果命名的文件不存在,那麼它將使用使用者的預設權限等創建,並將來自標準輸入的數據寫入其中。

mktemp實用程序不是標準的,但通常可用。

上述函式模仿了 Debian 軟體包手冊中描述的行為spongemoreutils


使用tee代替sponge將不是一個可行的選擇。你說你已經嘗試過了,它似乎對你有用。它可能有效,也可能無效。它依賴於管道中命令的啟動時間(它們幾乎是同時啟動的),以及輸入數據文件的大小。

以下是一個範例,顯示了 usingtee不起作用的情況。

原始文件是 200000 字節,但在管道之後,它被截斷為 32 KiB(這很可能對應於我係統上的一些緩衝區大小)。

$ yes | head -n 100000 >hello
$ ls -l hello
-rw-r--r--  1 kk  wheel  200000 Jan 10 09:45 hello
$ cat hello | tee hello >/dev/null
$ ls -l hello
-rw-r--r--  1 kk  wheel  32768 Jan 10 09:46 hello

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