7

一時変数を使用せずにこれをすばやく行う方法はありますか?組み込み関数はありますか?

編集:答えの人に感謝します。質問を明確にする必要があるようですが、ほとんどの場合、皆さんは正しく想定しています。2つのファイルがあり、ファイル名の名前が逆になっています。

  • ファイルAの名前はB-name.fileです。
  • ファイルBの名前はA-name.fileです。

ファイルAの名前をA-name.file、ファイルBの名前をB-name.fileにします。

私は同意します、状況は頻繁には起こりませんが、それは私に起こっただけであり、私は迅速な修正を望んでいました。

4

6 に答える 6

12

これは、.bashrc、.zshrc、または構成ファイルに配置するだけで、小さなヘルパーで実行できます。

function swap() { mv "$1" "$1._tmp" && mv "$2" "$1" && mv "$1._tmp" "$2"; }

そしてそれを通常の機能として使用します:

$ cat a b
Alfa
Beta

$ swap a b && cat a b
Beta
Alfa
于 2014-06-27T17:39:13.710 に答える
10

Darwin/Mac OS X にはexchangedata()システム コールがあります。

この関数は、 path1path2exchangedata()によって参照されるファイルの内容をアトミックに交換します。つまり、すべての同時プロセスは、交換前の状態または交換後の状態のいずれかを参照します。ファイルが一貫性のない状態にあることは決してわかりません。

ただし、実際には、特にサポートしているいくつかのファイルシステム (Apple の HFS や HFS+ など) でしか機能せず、他のシステムで同様のシステムコールを見たことがありません。これを行う移植可能な方法は、3 番目の一時ファイル名を使用することであり、操作はアトミックではありません。

于 2010-01-01T00:39:01.323 に答える
5

わかりました、ばかげた質問ですが、(シェルスクリプトで)次のようなことを単純にできないのはなぜですか:

mv $fileA $fileA.$$
mv $fileB $fileA
mv $fileA.$$ $fileB

もちろん、一時ファイルを使用しますが、他の回答よりも簡潔です。

于 2009-12-31T22:26:05.583 に答える
3

シェル スクリプト レベルでは、標準コマンドはなく、名前の変更には少なくとも一時ファイル名が含まれます (異なるファイル システム上のファイルに注意してください!)。

C コード レベルでは、ファイル名を交換するためにすべてのマシンで利用できる標準関数はありません。その要因の 1 つは、異なるファイル システム上のファイルを処理する問題です。

単一のファイル システムの場合:

file1=one-file-name
file2=tother-file
file3=tmp.$$

trap "" 1 2 3 13 15
ln $file1 $file3
rm $file1
ln $file2 $file1
rm $file2
ln $file3 $file2
rm $file3
trap 1 2 3 13 15

これは完全に確実というわけではありませんが、$file1 と $file2 が同じファイル システム上にある場合 (そして、$file3 が同じファイル システム上の名前であると想定しています) は、ある程度妥当な概算です。すべての疣贅に対処するためにそれを修正することは...重要です。(たとえば、$file1 == $file2 を考えてみてください。)

このコードは、C プログラムが作成しなければならないシステム コール ( lnto map tolink()およびrmto map to ) をほぼシミュレートしていunlink()ます。新しい (わずか 20 年しか経っていない) 関数rename()は、おそらく良い効果を得るために使用できます。mvリンクと削除の代わりにコマンドを使用すると、必要に応じてファイルがファイル システム間で移動されます。それは役に立つかもしれません-または、意図しないときにディスク容量がいっぱいになることを意味する場合があります. 途中でエラーから回復することも、完全に簡単ではありません。

于 2009-12-31T22:19:32.853 に答える
1

「ファイル名を入れ替える」とはどういう意味ですか? ファイルシステムについて話しているのですか、それともプログラム内の変数について話しているのですか?

プログラムが C++ で、文字列に 2 つのファイル名があり、それらを交換したい場合は、std::swap を使用します。これは、プログラム内の変数のみを変更します。

std::string filenameA("somefilename");
std::string filenameB("othername");

std::swap(filenameA, filenameB);
std::cout << filenameA << std::endl; // prints "othername"

ディスク上に 2 つのファイルがあり、名前の内容を互いに交換したい場合、いいえ、ハード リンクを保持したい場合、簡単に交換する方法はありません。「安全な保存」を実行したいだけの場合、UNIX の rename() システム コールは、アトミック操作で宛先ファイルをソース ファイルと一緒に上書きします (基礎となるファイル システムでサポートできる限りアトミックに)。したがって、次のように安全に保存します。

std::string savename(filename);
savename += ".tmp";
... write data to savename ...
if (::rename(savename.c_str(), filename.c_str()) < 0) {
  throw std::exception("oops!");
}

本当に本当にディスク上のファイルを交換する必要がある場合 (たとえば、バックアップ コピーを保持するため)、ハードリンクに入ります。注: ハードリンクはすべてのファイル システム (特に一部の SMB ファイル共有) でサポートされているわけではないため、必要に応じてバックアップを実装する必要があります。一時ファイル名は必要ですが、一時データ ストアは必要ありません。link() と unlink() を使用して手動で実装することもできますが (覚えておいてください: UNIX ではファイルに複数のハード リンクを含めることができます)、rename() を使用するだけの方が簡単です。ただし、スワップを完全にアトミックに行うことはできません。

oldfile が "filname.dat" で、newfile が "filename.dat.bak" であると仮定すると、次のようになります。

::link(oldfile, tempfile);
::rename(newfile, oldfile);
::rename(tempfile, newfile);

リンク後にクラッシュすると、新しいデータが newfile に、古いデータが oldfile と tempfile に保存されます。最初の名前変更後にクラッシュすると、新しいデータが oldfile に、古いデータが tempfile に保存されます (ただし、newfile には保存されません)。

于 2009-12-31T22:35:55.860 に答える
1

おそらくそれは次のように行うことができます:

file_B = fopen(path_b, 'r');
rename(path_a, path_b);

file_B_renamed = fopen(path_a, 'w');
/* Copy contents of file_B into file_B_renamed */
fclose(file_B_renamed);
fclose(file_B);

inode番号からハードリンクを作成する方法があるかもしれません(私はPOSIX仕様を調べていますが、私はそれに賭けません)。最終的には次のようなことになります

file_B = fopen(path_b, 'r');
rename(path_a, path_b);
make_hardlink(file_B, path_a);
于 2009-12-31T22:20:23.023 に答える