是否有海綿的標準替代品將文件通過管道傳輸到自身?
我經常想做這樣的事情:
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" )
這個
mysponge
shell 函式將標準輸入上的所有可用數據傳遞到一個臨時文件。當所有數據都被重定向到臨時文件時,收集的數據被複製到函式參數命名的文件中。如果不將數據附加到文件中(即
-a
不使用),並且如果給定的輸出文件名引用現有的正常文件,如果它不存在,則使用mv
(如果文件是現有的正常文件,首先嘗試使用 GNU 將文件模式轉移到臨時文件chmod
)。如果輸出不是正常文件(命名管道、標準輸出等),則數據以cat
.如果命令行上沒有給出文件,則收集的數據將發送到標準輸出。
最後,臨時文件被刪除。
函式中的每一步都依賴於上一步的成功完成。如果一個命令失敗(它可能包含重要數據),則不會嘗試刪除臨時文件。
如果命名的文件不存在,那麼它將使用使用者的預設權限等創建,並將來自標準輸入的數據寫入其中。
該
mktemp
實用程序不是標準的,但通常可用。上述函式模仿了 Debian 軟體包手冊中描述的行為。
sponge
moreutils
使用
tee
代替sponge
將不是一個可行的選擇。你說你已經嘗試過了,它似乎對你有用。它可能有效,也可能無效。它依賴於管道中命令的啟動時間(它們幾乎是同時啟動的),以及輸入數據文件的大小。以下是一個範例,顯示了 using
tee
不起作用的情況。原始文件是 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