ファイルが必要なコマンドに文字列を渡すにはどうすればよいですか?

ファイルが必要なコマンドに文字列を渡すにはどうすればよいですか?

プログラムがcook1つのパラメータ、つまり調理する食べ物のレシピを含むテキストファイルのパス名を取るとしましょう。スクリプトからプログラムを呼び出しbash、文字列変数にレシピを含めたとしましょう。

#!/bin/bash

the_recipe="$(cat << EOF
wash cucumbers
wash knife
slice cucumbers
EOF
)"

cook ...  # What should I do here? It expects a file, but I only have a string.

ファイル名引数が必要な場合は、コマンドにレシピをどのように渡しますか?

私はファイルを渡すために一時ファイルを作成することを検討しましたが、それに別の方法があるかどうか疑問に思いました。

答え1

/dev/stdin標準入力を表す「偽」ファイル名を使用できます。

したがって、以下を実行してください。

echo "$the_recipe" | cook /dev/stdin

echoコマンドとパイプは、指定された変数の内容を次のコマンドの標準入力に送信しますcook。次に、標準入力(別々のファイル記述子)を開き、読み込みます。

答え2

シェルのプロセス置換機能を使用する別の方法は、オペレーティングbashシステムに応じて名前付きファイル記述子()の下または下にFIFOを生成することです。代替構文()はFIFOまたはFDの名前で置き換えられ、その中のコマンドはバックグラウンドで実行されます。/tmp/var/tmp/dev/fd/*<(cmd)

cook <(printf '%s\n' "${the_recipe}")

これで、コマンドはcook変数の内容をファイルにあるかのように読み込みます。

これは複数の入力ファイルでも機能します。

cook <(printf '%s\n' "${the_1st_recipe}") <(printf '%s\n' "${the_2nd_recipe}")

答え3

これはアプリケーションの機能によって異なります。名前付きファイルの使用を主張することも、主張しないことも、見つかったファイルの使用を主張することも、主張しないこともあります。

匿名パイプ

一部のアプリケーションはどこからでも入力を読み込みます。通常、デフォルトでは標準入力から読み取られます。文字列形式のデータがあり、それをアプリケーションの標準入力に渡したい場合は、いくつかの方法があります。パイプを介して情報を渡すことができます。

printf '%s' "$the_recipe" | cook     # passes $the_recipe exactly
printf '%s\n' "$the_recipe" | cook   # passes $the_recipe plus a final newline

echoシェルによってバックスラッシュが壊れる可能性があるため、ここでは使用しないでください。

アプリケーションがファイルパラメータを使用する必要がある場合は、-標準入力を許可できます。これは一般的な慣例ですが、体系的ではありません。

printf '%s\n' "$the_recipe" | cook -

アプリケーションに実際のファイル名が必要な場合は、それを渡して/dev/stdin標準入力を表します。

printf '%s\n' "$the_recipe" | cook /dev/stdin

一部のアプリケーションでは、これだけでは不十分です。特定の拡張子を持つなど、特定の属性を持つファイル名が必要な場合、または一時ファイルが生成される書き込み可能ディレクトリにファイル名が必要です。この場合、通常は一時ファイルが必要ですが、時には名前付きパイプで十分です。

名前付きパイプ

パイプ名を指定できます。完全性のためにこれに言及しますが、最も便利な方法はほとんどありません。ディスクからデータを取得しないようにします。アプリケーションに名前が制限されたファイルが必要ですが、ファイルを見つけることが不要な場合に適しています。

mkfifo named.pipe
printf '%s\n' "$the_recipe" >named.pipe & writer=$!
cook named.pipe
rm named.pipe
wait "$writer"

(エラー確認は省略しました。)

一時ファイル

申請書に閲覧可能ファイルを使用するには、一時ファイルを作成する必要があります。検索可能なファイルは、アプリケーションが一度に一部を読みながら移動できるファイルです。パイプはこれを許可しません。戻るのではなく、最初から最後まで順番に読む必要があります。

Bash、ksh、zshには、一時ファイルを介して文字列を入力に渡す便利な構文があります。 (すでに存在していても)常に文字列に改行文字を追加します。

cook <<<"$the_recipe"

別のシェルを使用したり一時ファイルを含むディレクトリを制御したりするには、一時ファイルを手動で作成する必要があります。ほとんどのユニスは以下を提供します。mktemp便利一時ファイルを安全に作成してください。 (この方法は絶対に使用しないでください… >/tmp/temp.$$。他のユーザーとして実行されている他のプログラムもファイルをハイジャックできます。)これは一時ファイルを作成し、中断したときに削除を処理するスクリプトです。

tmp=
trap 'rm -f "$tmp"' EXIT
trap 'rm -f "$tmp"; trap "" HUP; kill -INT $$' HUP
trap 'rm -f "$tmp"; trap "" INT; kill -INT $$' INT
trap 'rm -f "$tmp"; trap "" TERM; kill -INT $$' TERM
tmp=$(mktemp)
printf '%s\n' "$the_recipe" >"$tmp"
cook "$tmp"

一時ファイルが作成される場所を選択するには、TMPDIRという環境変数を設定しますmktemp。たとえば、一時ファイルの既定の場所の代わりに現在のディレクトリに一時ファイルを作成するには、次のようにします。

tmp=$(TMPDIR="$PWD" mktemp)

$PWD代わりに使用すると.絶対ファイル名が提供されるため、同じファイルを再割り当てすることを心配するcdことなく、安全にスクリプトを呼び出すことができます。)$tmp

アプリケーションに特定の拡張子を持つファイル名が必要な場合は、一時ディレクトリを作成してその中にファイルを作成する必要があります。一時ディレクトリを作成するにはを使用しますmktemp -dTMPDIR一時ディレクトリが作成される場所を制御するには、環境変数をリセットします。

tmp=
trap 'rm -rf "$tmp"' EXIT
trap 'rm -rf "$tmp"; trap "" HUP; kill -INT $$' HUP
trap 'rm -rf "$tmp"; trap "" INT; kill -INT $$' INT
trap 'rm -rf "$tmp"; trap "" TERM; kill -INT $$' TERM
tmp=$(mktemp -d)
printf '%s\n' "$the_recipe" >"$tmp/myfile.ext"
cook "$tmp/myfile.ext"

答え4

より複雑なソリューションを試す前に、そのバージョンがパラメータ(ダッシュ)をファイル名でサポートしていることをcook確認してください。-このルールがサポートされている場合は、cook次のように標準入力から読み取るように指示します。

echo "$the_recipe" | cook -

または

cook - <<<"$the_recipe"

関連情報