file
両方のファイル(および)file_1
のファイル名を変更する必要があります。次のコードを使用しています。
mv file .phfile
mv file_1 file
mv .phfile file
この方法はうまくいきますが、バグが多く、時にはデータが失われる可能性があります。もっと良い方法がありますか?
答え1
答え2
既存のUnixシステムではファイルを交換する低レベルの方法がないため、中間の一時的な名前を使用する必要があります。堅牢性のために、一時名が他のプログラムで使用されず(したがって使用されているmktemp
)、ファイルの1つと同じファイルシステムに存在することを確認してください。それ以外の場合は、ファイル名が変更されるのではなく、不必要にコピーされます。 。
swap_files () {
tmp_name=$(TMPDIR=$(dirname -- "$1") mktemp) &&
mv -f -- "$1" "$tmp_name" &&
mv -f -- "$2" "$1" &&
mv -f -- "$tmp_name" "$2"
}
swap_files file file_1
エラーが発生した場合、最初のファイルはまだ一時的な名前を持つことができますが、2番目のファイルは移動されたか移動されていない可能性があります。ダウンタイムとクラッシュが発生した場合に堅牢でなければならない場合、2つの個人的なバリエーションが一時的な名前で回復しやすくなります。
swap_files2 () {
tmp_dir1=$(TMPDIR=$(dirname -- "$1") mktemp -d .swap_files.XXXXXXXXXXXX) &&
tmp_dir2=$(TMPDIR=$(dirname -- "$2") mktemp -d .swap_files.XXXXXXXXXXXX) &&
mv -f -- "$1" "$tmp_dir1/" &&
mv -f -- "$2" "$tmp_dir2/" &&
mv -f -- "$tmp_dir1/"* "$1" &&
mv -f -- "$tmp_dir2/"* "$2" &&
rmdir -- "$tmp_dir1" "$tmp_dir2"
}
再起動後も一時ディレクトリが.swap_files.????????????
続くと、停電によりファイル交換が中断されたことを意味します。ファイルの 1 つは所定の位置に移動しましたが、もう 1 つは移動していない可能性があるため、ここのコードは目的のリカバリの種類に応じてすべてのケースを処理するわけではありません。
最新のLinuxカーネル(2014年6月にリリースされた3.15ベース)ファイル交換のためのシステムコールがあります。renameat2(…, RENAME_EXCHANGE)
しかし、汎用コマンドラインユーティリティはないようです。 glibcのサポートも最近追加されました(2.28、2018年8月発売)。
答え3
パーティーに少し遅れたが、最新バージョンと以前のバージョンのLinuxでは、スワップファイルの名前を自動的に指定できます。tcc
または使用gcc
(すべての主要なLinuxディストリビューションで利用可能)タイムリーな生産あなた自身は、正しいカーネルシステムコールを取得して使用する低レベルのツールです。サードパーティ製のツールは必要ありません。
swapname() {
tcc -run - "$@" <<"CODE"
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/syscall.h>
// Ubuntu 18.04 does not define RENAME_EXCHANGE
// Value obtained manually from '/usr/include/linux/fs.h'
// You should switch to RENAME_EXCHANGE on modern systems
// Just remove the following line, then remove the `local_`
// prefix where it appears later in this function.
int local_RENAME_EXCHANGE = (1 << 1);
int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "Error: Could not swap names. Usage: %s PATH1 PATH2\n", argv[0]);
return 2;
}
int r = syscall(
SYS_renameat2,
AT_FDCWD, argv[1],
AT_FDCWD, argv[2],
local_RENAME_EXCHANGE
);
if (r < 0) {
perror("Error: Could not swap names");
return 1;
}
else return 0;
}
CODE
}
次のように、このbash機能を実行すると、ファイル名がクリーンでアトミックに置き換えられます。
swapname "/path/to/file-1" "/path/to/file-2"
両方のファイルが同じファイルシステムのマウントポイントにある必要がありますrenameat2
。RENAME_EXCHANGE
マニュアルページのエラーセクションを参照してくださいrenameat2
(例:rename(2)
) 詳細をご覧ください。
TCCの代わりにGCCを使用してください
gcc
代わりに使用するには、tcc
で始まる行を削除し、tcc -run ...
その場所に次の行を追加します。
( EXEC="$(mktemp)" && gcc -x c - -o "$EXEC" && "$EXEC" "$@"; rm "$EXEC" ) <<"CODE"
答え4
これが私が使用したものです。
file1=1stfile
file2=2ndfile
tempdir="$(mktemp -d)"
mv "$file1" "$tempdir/tmpfile" &&
mv "$file2" "$file1" &&
mv "$tempdir/tmpfile" "$file2" &&
rm -rf "$tempdir"