Bashパイプラインで生のバイナリデータを処理する方法は?

Bashパイプラインで生のバイナリデータを処理する方法は?

ファイルを引数として受け取り、ファイルが存在することを確認し、stdinからインポートされたすべての内容をファイルに書き込むbash関数があります。この単純な解決策はテキストには機能しますが、任意のバイナリデータには問題があります。

echo -n '' >| "$file" #Truncate the file
while read lines
do  # Is there a better way to do this? I would like one...
    echo $lines >> "$file"
done

答え1

$IFSあなたのアプローチは、読み取りを分割するために使用される区切り文字()のスペースに書き込むすべての項目に改行を追加することです。改行に分けるのではなく、全体を渡してください。上記のコード全体を次のように単純化できます。

 cat - > $file

切り捨てビットは必要ありません。これにより、STDIN ストリーム全体が切り捨てられ、ここに書き込まれます。

編集する:zshを使用している場合は、> $file代わりにcatを使用できます。ファイルにリダイレクトして切り捨てますが、STDINを受け入れるのを待つものがあれば、その時点で読み込まれます。私の考えでは、bashを使ってこれを行うことができますが、いくつかの特別なモードを設定する必要があります。

答え2

readテキストファイルを文字通り読み取るには、次の2つの方法で出力を処理するプレーンを使用しないでください。

  • readこの機能をオフにする\ために使用されるエスケープ文字として解釈されます。read -r
  • read;;の文字を単語に分割してオフにするには、空の文字列に$IFS設定します。IFS

テキストファイルを1行ずつ処理する一般的な慣用語は次のとおりです。

while IFS= read -r line; do …

このイディオムの説明については、以下を参照してください。while IFS= read代わりに、なぜそれほど頻繁に使用されますかIFS=; while read..

文字列を文字通り作成するには、プレーンを使用せずにecho2つの方法で文字列を処理します。

  • 一部のシェルはechoバックスラッシュエスケープを処理します。 (Bashでは、xpg_echoこのオプションを設定するかどうかによって異なります。)
  • -n一部の文字列は、または同じオプションで処理されます-e(正確な設定はシェルによって異なります)。

文字通り文字列を印刷する移植可能な方法はを使用することですprintf。 (入力のように見えないオプションがわからない限り、bashには良い方法はありませんecho。)追加する場合は、最初の形式を使用して正しい文字列を印刷します。改行文字の場合は、2番目の形式を使用してください。

printf %s "$line"
printf '%s\n' "$line"

これは処理にのみ適しています。テキスト、なぜなら:

  • ほとんどのシェルは入力からヌル文字をブロックします。
  • 最後の行を読むときに末尾に改行文字があるかどうかを知る方法はありません。 (一部の古いシェルは、入力が改行文字で終わらないと、より大きな問題がある可能性があります。)

シェルはバイナリデータを処理できませんが、uniceの最新のユーティリティバージョンのほとんどは任意のデータを処理できます。すべての入力を出力に渡すには、cat.Off-topicを使用してくださいecho -n ''。何もしない複雑で移植性のない方法です。echo -n同様に良い(場合によっては異なりますが)、はるかに:簡単で完全に移植可能です。

: >| "$file"
cat >>"$file"

またはより簡単に、

cat >|"$file"

スクリプトではデフォルトではオフになっているため、>|通常使用する必要はありません。noclobber

答え3

これはまさにあなたがしたいことをします:

( while read -r -d '' ; do
    printf %s'\0' "${REPLY}" ;
  done ;

  # When read hits EOF, it returns non-zero which exits the while loop.
  # That data still needs to be output:
  printf %s "${REPLY}"
) >> ${file}

ただし、メモリ使用量に注意してください。これはnullで区切られた方法で入力を読み取ります。

もしなければ\0 無効入力にバイトが含まれている場合、bashは最初に入力の内容全体をメモリに読み込み、出力する必要があります。

トリミングステップに関して:

echo -n '' >| "$file" #Truncate the file

より簡単で同等のアプローチは次のとおりです。

> ${file}   #Truncate the file

関連情報