ترفند مخفی لینوکس: دستور mv که کار سه تا دستور رو با هم انجام میده!

تا حالا شده بخوای دوتا فایل رو با هم جابجا کنی؟ راه سنتیش اینه که اولی رو موقت تغییر نام بدی، دومی رو بیاری جاش، بعد فایل موقت رو بذاری جای دومی! خیلی مسخره و دردسرسازه، مگه نه؟ تازه تو یه لحظه کوتاه، ممکنه یکی از فایلها اصلاً وجود نداشته باشه و سیستم گیج بشه.
خوشبختانه از نسخه ۹.۵ به بعد، ابزار GNU coreutils یه راه حل خفن به اسم mv --exchange گذاشته جلو پای ما که کار رو خیلی راحت کرده. تو این مقاله قراره ببینیم این قابلیت چطور کار میکنه، چطور چکش کنیم و چه اشتباهاتی نباید موقع استفاده ازش بکنیم.
روش قدیمی: سه بار جابجایی و دردسرهای فایل موقت
فرض کن دوتا فایل کانفیگ به اسمهای nginx.conf و nginx.conf.new داری و میخوای جدید جای قدیم بشه و فایل قدیمی هم دستنخورده بمونه. با دستور کلاسیک mv command باید این شکلی عمل میکردی:
mv nginx.conf nginx.conf.tmp
mv nginx.conf.new nginx.conf
mv nginx.conf.tmp nginx.conf.newاین روش دو تا مشکل اساسی داره:
- خلاء زمانی وجود داره: بین دستور اول و دوم، فایل
nginx.confاصلاً وجود نداره! اگه تو همون صدم ثانیه یه سرویس بخوادش، با خطا روبرو میشه. - نصفه کاره موندن کار: اگه دستور دوم به هر دلیلی خطا بده، با یه فایل موقت و یه سیستم به هم ریخته تنها میمونی.
حالا آپشن exchange همین کار رو تو یه دستور تکی و تمیز انجام میده:
mv --exchange nginx.conf nginx.conf.newجابجایی فایلها با mv –exchange
آپشن --exchange به دستور mv میگه که این دوتا مسیر رو تو یک عملیات اتمیک با هم جابجا کن. این یعنی درایور سیستمعامل با کمک کرنل و با استفاده از سیستمکال renameat2() و Flag مربوط به RENAME_EXCHANGE این کار رو طوری انجام میده که تو هیچ لحظهای فایل گم نشه.
چطور بفهمیم سیستم ما از این قابلیت پشتیبانی میکنه؟
اول از همه باید ورژن coreutils رو چک کنی:
mv --versionنکته مهم اینه که شماره ورژنها اعشاری نیستن؛ مثلاً نسخه 9.11 از نسخه 9.5 جدیدتره! میتونی از این دستور هم برای چک کردن کمک بگیری:
mv --help | grep exchangeاگه چیزی چاپ نشد، یعنی توزیع لینوکس شما هنوز این قابلیت رو نداره.
تست عملی جابجایی دو فایل
بیاید دوتا فایل تستی بسازیم:
echo "config A" > a.conf
echo "config B" > b.confحالا با دستور زیر جابجاشون میکنیم:
mv --exchange a.conf b.confو نتیجه رو میبینیم:
cat a.conf b.confconfig B
config Aبه همین سادگی! محتوای فایلها جابجا شد بدون اینکه نیاز به فایل موقت باشه.

جابجایی دو تا دایرکتوری (و اشتباهی که خودم کردم!)
این ترفند برای دایرکتوریها هم کار میکنه و اتفاقاً جذابترم هست. اما بار اولی که تستش کردم به این خطا خوردم:
mkdir release-old release-new
touch release-old/v1 release-new/v2
mv --exchange release-old release-newmv: cannot exchange 'release-old' and 'release-new/release-old': Unknown error -1دلیلش اینه که وقتی آرگومان آخر یه دایرکتوری موجود باشه، دستور mv فکر میکنه میخوای فایل رو بریزی توش! راه حلش استفاده از آپشن -T (یا همون --no-target-directory) است:
mv -T --exchange release-old release-new
ls release-old release-newحالا کل ساختار دایرکتوریها بدون توجه به حجمشون با هم جابجا شدن.
جاهایی که این دستور به دادمون میرسه
- آپدیت کانفیگها: میتونی فایل جدید رو جایگزین کنی و فایل قبلی رو برای بازگشت سریع (Rollback) نگه داری.
- سوئیچ کردن دایرکتوریهای انتشار (Release): آپدیت نسخه سایت تو پوشهها در یک قدم.
- برگشت به عقب: اجرای دوباره همون دستور، همهچیز رو به حالت اول برمیگردونه.
محدودیتهایی که باید بدونید
هر دو مسیر باید روی یک Filesystem باشن
این قابلیت فقط روی یک Filesystem کار میکنه. اگه بخوای یه فایل رو با یه مسیر روی tmpfs یا حافظه رم جابجا کنی، کرنل با خطای نامفهوم Unknown error -1 جلوت رو میگیره چون جابجایی اتمیک بین دو تا دیسک یا ساختار جداگانه امکانپذیر نیست.

پشتیبانی خود Filesystem
طبیعتاً ساختار زیرساختی و Filesystem شما مثل ext4، Btrfs یا XFS باید از این قابلیت پشتیبانی کنن که خوشبختانه سیستمهای مدرن امروزی مشکلی ندارند.
نتیجهگیری
دستور mv --exchange یکی از اون ابزارهای کوچیک اما فوقالعاده کاربردیه که کارهای خستهکننده توی Terminal رو خیلی راحتتر میکنه. اگه از توزیعهای مدرن مثل فدوا یا دبیان استفاده میکنی، همین الان میتونی ازش لذت ببری!




