Bashで(仮想)ファイルの読み取りと書き込みを継続的に行う必要があります間にファイルを閉じずに。ファイルを読み取りと書き込み用に開き、stdinから読み取り、読み取ったものをファイルに書き込み、ファイルから読み取り、stdoutに書き込むプログラムを探しています。 netcat
に少し似ていますが、ファイル用です。
問題のファイルは/ sys内の仮想ファイル(私が取り組んでいるもののカスタムのもの)であり、コマンドを書き込んで読み取り、応答を受信します。書き込みと後続の読み取りは同じセッションで実行する必要があります。つまり、同じファイル記述子上で、間に閉じずに。
Cで簡単に実行できます--open("file", O_RDWR)
、write()
、read()
-注:seek()
の必要はありません。
標準のGNUツールはありますか、それとも作成する必要がありますか?
切り捨てなしで読み取り+書き込みモードでファイルを開くためのリダイレクト演算子は、すべてのボーンのようなシェルで<>
です(open(file, O_RDWR|O_CREAT)
にマップされます(ただし、zsh
もO_NOCTTY
をスローします)またはfopen(file, "w+")
):
exec 3<> "$file"
ファイル記述子3の$file
を読み取り+書き込みモードで開きます(切り捨てたり、存在しなかった場合は作成したりしません)。
ただし、ksh93
とzsh
のみがseeking演算子を持っています。 dd
はシークできますが、逆方向にはシークできません。また、zsh
以外のシェルは変数にNULバイトを含めることができないことに注意してください。
zsh
:
zmodload zsh/system
exec 3<> $file
sysread -i 3 -c 2 var # a read() of 2 bytes
sysseek -u 3 0 # seek back to beginning
# or sysseek -u 3 -w current -2 # to seek back 2 bytes
syswrite -o 3 something-else
exec 3<&- # close
ksh93
:
exec 3<> "$file"
var=$(dd bs=2 count=1 <&3 2>/dev/null; echo .)
var=${var%?}
exec 3<#((0)) # seek to beginning
# or exec 3<#((CUR-2)) # to seek back 2 bytes
print -ru3 something-else
移植性がありますが、オフセット2で2バイトを読み書きするように、必要なオフセットごとにファイルを数回開くことができます(zsh
を使用していない場合は値0のバイトではない場合)。
var=$(dd bs=2 count=1 skip=1 < "$file"; echo .)
var=${var%?}
printf %s something-else | dd bs=2 seek=1 1<> "$file"
または:
printf %s something-else | dd bs=2 seek=1 of="$file" conv=notrunc
同じファイルの読み取りと書き込みを行うために、ksh93
には他に2つの興味深いリダイレクト演算子があります。
tr 01 10 < file >; file
tr
の出力を一時ファイルに保存し、tr
が成功した場合は、名前をfile
に変更します(ファイルは新しく作成されるため、権限と所有権が異なる可能性があることに注意してください) )。
tr -d 0 < file 1<>; file
標準/ボーンtr -d 0 < file 1<> file
と同じですが、tr
が成功した場合、file
が書き込みを終了したところでtr
が切り捨てられます。これは、入力を読み取るよりも出力が少ないフィルターコマンド、より正確には、以前に書き込んだデータを読み取らないコマンドに使用できます。
また、zsh
には=(...)
形式のプロセス置換があります。これは次のように使用できます。
mv =(tr 01 10 < file) file
(ksh93
の>;
と同様の効果と警告があります)。または:
cp =(tr 01 10 < file) file
これはfile
の属性を保持しますが、余分なコピーを意味します。
これで、同じファイル記述子を使用して同じオフセットで読み取りと書き込みを行う必要があり、zshもksh93も使用できない場合は、いつでもPerl
/python
/Ruby
に戻すことができます。 ...。
Perl -e '
open F, "<>", "file" or die "open: $!";
read F, $var, 1;
seek F, 0, 0;
print F "something-else"'
質問の更新バージョンを再度読んだ後、ファイルは通常のシーク可能なファイルではなく、ソケットまたは双方向パイプのように動作しているように見えます。
その場合、それは次の問題である可能性があります。
socat - file:your-file
または:
(cat >&3 3>&- & cat <&3 3<&-) 3<> your-file
stdin/stdoutから/への読み取りとして、そのファイルとの間でデータをフィードします。
各cat
は、シェルによって開かれたファイル記述子3の独自のコピーに対して読み取り/書き込みを行いますが、同じファイル記述を開くを共有するため、同等である必要があります。
翻訳のみを行わない限り、安全に同時に読み取りと書き込みを行うことはできません(翻訳を行っても、ファイルが終了する可能性があります)プログラムがエラーで終了した場合は、「半分翻訳」されます)。
tee
とsponge
の組み合わせが本当に必要なようです。 moreutils からsponge
を使用して、標準入力を吸収し、それをファイルに書き出すことができます。 tee
を使用して、入力を複数の出力に複製できます。
最終結果は次のようになります。
_command < filename | tee >(sponge filename)
_
>()
は プロセス置換 の例です。この場合、>(sponge filename)
は、sponge
が書き込むtee
の標準入力に向かうFIFOへのパスに置き換えられます。 .tee
は、入力をstdoutに個別に書き込みます。
これが例です。出力がstdoutに書き込まれ、ファイルに書き込まれていることがわかります。
_$ echo 'foo bar' > file
$ sed 's/foo/qux/' < file | tee >(sponge file)
qux bar
$ cat file
qux bar
_