私は読んだ:ファイルを適切に変更する方法はありますか?
一時ファイルを生成しない命令を使ってその場でファイルを修正する方法があるかどうか疑問に思います。ディレクトリを作成
mkdir read_only
し、read_onlyにいくつかのファイルを作成するとします。ファイルの作成が正常に完了したら、を実行しますchmod 555 read_only
。これで、一時ファイルを使用せずにファイルを変更できますか?特に、私はbashスクリプトを介して実行できるソリューションが欲しいです。これが可能かどうかは知りたくありません。また、解決策を探しています。これまでbash / unixコマンド管理を使用して得られたすべてのアイデアは、一時ファイルを生成します。
編集:私の質問は重複していないようです。「書き込み」権限を持つファイルを編集できますが、親ディレクトリは編集できませんか?次の理由で:
- 私は単に「はい」と尋ねる以上の解決策を探しています。そして彼らが尋ねるのは「はい」だけでした。
- おそらく、重複した回答が私の質問に完全に答えていない可能性があります。 Bashスクリプトに入れることができるコマンドを要求します。
答え1
ディレクトリ内のファイルを作成または削除するには、ディレクトリへの書き込み権限が必要ですが、ディレクトリ内のファイルに書き込むことはできません。ほとんどのシェルコマンドは、出力ファイルが提供されると、単に書き込みのためにファイルを開き、ファイルの古いデータを置き換えます。リダイレクト>
演算子は既存のファイルを切り捨て(つまり、既存のファイルの内容を削除してファイルの長さがゼロ)、書き込みを開始します。リダイレクト>>
演算子を使用すると、データがファイルの末尾に追加されます。
ファイルの書き込みは、低レベルのインターフェイスによって提供される可能性によって制限されます。ファイルのバイトを所定の位置に上書きし、ファイルの末尾に追加し、ファイルを選択した長さに切り捨てることができます。次のバイトを前に移動している間(たとえば→ foobar
)fooNEWSTUFFbar
、バイトを挿入したり、後続のバイトを前に移動している間(たとえば→ foobar
)for
、バイトを削除することはできません。ただし、移動したいデータを読み取って新しい場所に書き込んでこれらの操作をシミュレートする場合は除外されます。
ファイルを適切に編集するときの問題は、問題が発生した場合(プログラムエラー、ディスクいっぱい、停電など)、ファイルの内容の一貫性を維持するのが難しいことです。そのため、強力なファイル処理には、新しいデータで一時ファイルを作成し、その一時ファイルを所定の場所に移動することが含まれることがよくあります。
ファイル編集のもう一つの制限は、読み書きに関連する複雑な操作がアトミックではないということです。これは、ファイルの変更中に他のジョブからファイルを読み取ろうとする場合にのみ問題になります。たとえば、最後の3バイトを読み取り()、新しいデータを書き込み(→)、最後に前の尾を追加(→)してに変更すると、同時foobar
リーダーはファイルの状態の他の部分も表示できます。部分的に作成されたデータのみを含みます。 。繰り返しますが、一時ファイルを所定の位置に移動することはアトミックな操作であるため、最初に一時ファイルに書き込むとこの問題は解決されます。fooNEWSTUFFbar
bar
foo
fooNEWSTUFF
fooNEWSTUFF
fooNEWSTUFFbar
fooNEWSTUFF
これらの制限を気にしない場合は、その場所でファイルを変更できます。データを追加するのは簡単です(>>
)。他のほとんどの変換はより複雑です。一般的な落とし穴は
somefilter <somefile >somefile
ファイルの内容に適用できませんsomefilter
:演算子は>
読み取りを開始する前に出力ファイルを切り捨てます。somefilter
Joey Hessのmoreutilsというファイルが含まれています。sponge
これで問題が解決しました。出力をにリダイレクトするのではなく、にパイプしてすべてのsomefile
入力sponge
を読み取るそれから読み取り入力で既存のファイルを上書きします。フィルタが失敗しても、まだ部分的なデータを取得できます。
somefilter <somefile | sponge somefile
ない場合、sponge
この問題を解決するための移植可能で簡単な方法は、最初にデータをメモリに読み込むことです。
content=$(cat somefile; echo a)
content=${content%a}
このecho a
ビットは、ファイルの終わりの改行を維持するために使用されます。コマンド置換は常に末尾の改行を削除します。その後、コンテンツをコマンドに渡すことができます。
printf %s "$content" | somefilter >somefile
これにより、ファイルの内容がフィルタ出力に置き換えられます。何らかの理由でコマンドが失敗すると、ファイルの元の内容は失われ、ファイルには失敗する前にコマンドで書き込まれたすべてのデータが含まれます。
ほとんどのシェルはヌルバイトをサポートしていないため、この方法はバイナリファイルでは機能しません。
ファイルを修正するもう1つの方法は、次を使用することです。ed
sedと非常によく似たエディタですsed
が、sedの1行ずつ作業するのではなく、ファイルをメモリにロードしてその場所に保存します。
ファイルをメモリにロードしたり一時ファイルを作成したりすることなく、標準のシェルツールを使用してファイルを操作するのは難しいですが、可能です。シェルリダイレクトとほとんどのテキスト処理ユーティリティは、ファイルに追加するか、最初から上書きすることを許可します。これにより、dd conv=notrunc seek=…
見つからない部分に影響を与えずにファイルのオフセット内のデータを上書きできます。ファイルを適切に変更する方法はありますか?例えば。
答え2
ディレクトリが読み取り専用ですが、ディレクトリ内のファイルが読み取り/書き込みの場合、そのファイルを上書きするのを防ぐ方法はありません。
スクリプトで一般的なリダイレクトを使用してファイルに書き込みます>
。>>
cp
できないことは、ディレクトリに新しいファイルを作成し、既存のファイルの上に名前を変更することです。名前の変更は原子的に発生するため、通常は新しいファイルを作成して名前を変更することをお勧めします。これにより、データの損失を防ぎ、一般名でファイルを読み取る他のプロセスが更新中にファイルの一部のみを表示するのを防ぎます。
新しいファイルを作成して名前を変更する機能がないということは、ファイルを更新するときに必要な保証について非常に慎重に考える必要があることを意味します。
答え3
真珠Tie::File
基準寸法真の内部編集機能を提供します。
perl -MTie::File -e '
tie @a,"Tie::File","your_file_here";
# Do something...
'
これにより、要素が@a
ファイル行に入り、@a
ファイルが読み取り専用ディレクトリにあっても、ファイルに対するすべての変更がファイルに反映されます。
答え4
カント。 sedまたはperl-i
スイッチを使用して読み取り専用ディレクトリのファイルを編集することはできません。正しく想定したように、必要な一時ファイルを生成することはできません。
$ ls -ld read_only/
dr-xr-xr-x 2 terdon terdon 4096 Apr 13 02:16 read_only/
$ ls -l read_only/file
-rw-r--r-- 1 terdon terdon 3 Apr 13 02:16 read_only/file
$ sed -i 's/a/A/' read_only/file
sed: couldn't open temporary file read_only/sedOEdv8L: Permission denied
$ perl -i -pe 's/a/A/' read_only/file
Can't remove read_only/file: Permission denied, skipping file.
しかし、Joseph.Rの素晴らしいPerlトリックを使用することができます。
$ perl -MTie::File -e 'tie @a,"Tie::File","$ARGV[0]"; $a[0]=~s/a/A/' read_only/file