単一ファイルをパイプライン全体の入出力として処理する[冗長]

単一ファイルをパイプライン全体の入出力として処理する[冗長]

おやすみなさい、

いくつかのパイプコマンドを使用してファイルの内容をフィルタリングし、結果を同じファイルに書き換えたいと思います。私が書いたようにできないことを知っています。待つ…

これは私のbashスクリプトです。

grep '^[a-zA-Z.:]' "$filepath" \
    | sed -r '/^(rm|cd)/d' \
    | uniq -u \
    > "$filepath"

だから代わりに、プロセス置換をうまく使うことができると思います。それから私は次のように書きました。

grep '^[a-zA-Z.:]' < <(cat "$filepath") | …

これも何も解決しませんでした。一時ファイルなど、どこかに入力ファイルの内容を「保存」するためのプロセスを置き換えたいと思います。プロセスの置き換えも理解できないようです。

「現在の場所」バージョンのスレッドを読みましたが、その記事では、またはいくつかのsed -iバイナリの特別なオプションを強調しましたが、sort -o一般的な解決策が必要です(すべてのパイプラインコマンドを満たす必要があることを意味します)。

まず、「標準パイプライン方式」がこれを行わないのはなぜですか?その下では何が起こっていますか?:/問題をどのように解決するのですか?誰でもお願いします説明する私に何が起こりましたか?

ありがとうございます。

ベストアンサー1

すでに述べたように、スポンジは以下に由来します。その他のユーティリティ大きい。 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シミュレーションには一時ファイルのみを使用してください。これは、パイプラインステップが失敗した場合に実際の内部フィルタリングがファイルを簡単に破損させる可能性があるためです。

以下で何が起こっているのかについては、両方ともシステムパイプを|使用<()し、一度に1つのバッファをIOに渡します。このメカニズムは一時ファイル(実際のファイルシステムファイルではない)を生成せず、入力全体を一度にメモリに保持するのを防ぎます。

おすすめ記事