Bashで/dev/fd/Xを書く移植可能な方法

Bashで/dev/fd/Xを書く移植可能な方法

ファイルを使用する前に削除したいので、この例ではpaste始める前にcol1、col2 ... col1000のリンクを解除したいと思います。

exec 3< col1 4< col2 ... 1002< col1000
rm col1 col2 ... col1000
paste /dev/fd/3 /dev/fd/4 ... /dev/fd/1002

これはGNU / Linux + bashでうまく機能します。ただし、/dev/fd/X他のシステムに移植することはできません。

私が使用できるbashコマンドの置き換えは次のとおりです。

exec 3< col1 4< col2 ... 1002< col1000
rm col1 col2 ... col1000
paste <(cat <&3) <(cat <&4) ... <(cat <&1002)

ただし、これを行うにはファイルごとに1つのプロセスが必要です。

すべてのシステムでBashと連携するように上記の内容を書くことはできますか?たぶん特別なBash構文がありますか?

ベストアンサー1

最も簡単な移植可能な解決策は、ファイル記述子番号を引数として使用し、ファイルpaste記述子リダイレクトを含む組み込み関数を使用してそれを繰り返す関数に置き換えることです。read

paste()
{
    at_least_one_read_succeeded=true
    while $at_least_one_read_succeeded
    do
        at_least_one_read_succeeded=false
        first_fd=true
        for fd in "$@"
        do
            if ! $first_fd
            then
                printf '\t'
            fi
            if IFS= read -r line <&"$fd"
            then
                at_least_one_read_succeeded=true
            fi
            printf '%s' "$line"
            first_fd=false
        done
        printf '\n'
    done
}

主な欠点は、シェルの組み込み機能が別々のシステムコールをread実行するしかないため、速度がはるかに遅いことです。readバイトごとに。同様にprintf、コマンドを呼び出すたびに少なくとも1つのwriteシステムコールを実行する必要があります(理論的には、最適化コンパイラとJIT VMが実行するのと同じ分析を使用して、この場合I / Oを最適化できるシェルを作成できます。 )。しかし、現在そのようなシェルは存在しません)。ほとんどの場合、最新のハードウェアではその違いはまだ無視できますが、例には何千ものファイルが含まれているため、実際にパフォーマンスが低下する可能性があり、これはユースケースにとって重要です。

もちろん、時間と労力を尊重することに加えて、シェルで独自にバッファリングされたI / Oをローリングするのを防ぐ方法はありません。たとえば、dd bs=4096 count=1一度に4096バイトを各FDの別々の変数として読み込み、改行が不足するまでその行をインポートできます。たとえば、という bash 配列を作成し、buffers次のようにbuffers[$fd]=$(dd bs=4096 count=1 <$&fd)読み取ることができます。${buffers[$fd]%%'$\n'*}正直に言うと、これを検討していてcolこれらのファイルをディスクに保存しないことが非常に重要な場合は、これらの列ファイルの内容全体を変数として読み取ることも検討できますbash。データサイズはわかりません。しかし、システムがbashその程度の割り当てを許可し、それbash自体を処理する場合本物これらのファイルがディスクに残らないようにすることも重要ですが、コンテンツが指定されたファイルにまったく届かないようにすることも十分に重要です。


しかし、一歩後ろに退ければ、これほど十分ではないでしょうか?

paste col1 col2 ... col1000 &  # background `paste`
# optionally, put a tiny sleep here
rm col1 col2 ... col1000
wait  # wait for `paste` to finish

col*正直なところ、ファイルがクリーンアップされない時間が常にあるからです(rmコードまたは以前に実行されていたコードにrm停電が発生した場合はどうなりますかpaste?)。ウィンドウが起動し、システムコールを介してすべてのパラメータに到達したpasteときにウィンドウが<= 1秒間持続する場合(最新のハードウェアでは1ミリ秒未満で十分です)、本当に悪いですか?open


考慮すべきもう一つのことは、一時ファイルシステムを使用することです。多くのオペレーティングシステムは、特定のパスにメモリ内ファイルシステムを提供します。たとえば、ほぼすべてのLinuxディストリビューションには、通常、各ユーザーが個人用ディレクトリを取得するマウントポイントが/runあります。電源がオフになったり、ボックスを再起動またはシャットダウンしたりすると、その中のすべての項目は保存されません。実行する必要がある他のシステムが何であるかはわかりませんが、そのシステムに一時メモリファイルシステムがあるかどうか、または再起動時にOSディレクトリによってクリアされることが保証されていることを確認することをお勧めします。tmpfs/run/$(id -u)tmpfs

おすすめ記事