การทำให้ไดเรกทอรีได้รับการป้องกันจาก 'rm -rf'


9

ฉันเพียงแค่สูญเสียข้อมูลบางอย่างในโฟลเดอร์ซึ่งเป็นโฟลเดอร์ภายใน B rm -rf Bหลังจากที่ทำ ก่อนที่ฉันจะรู้ว่าสิ่งที่ฉันทำมันจบลงแล้ว ตอนนี้ฉันได้เรียนรู้บทเรียนแล้วฉันต้องการทำให้โฟลเดอร์ของฉันงี่เง่าพิสูจน์เพื่อหลีกเลี่ยงในครั้งต่อไปเมื่อฉันทำสิ่งที่คล้ายกันและต้องการที่จะฆ่าตัวตาย

rmวิธีการหนึ่งที่ฉันสามารถคิดคือการเขียนฟังก์ชั่นการทุบตีและนามแฝงมัน .dontdeleteฟังก์ชั่นนี้จะดูในแต่ละโฟลเดอร์ย่อยสำหรับไฟล์ที่ซ่อนอยู่เช่น เมื่อพบว่ามันจะถามว่าฉันต้องการที่จะดำเนินการต่อไป ฉันไม่สามารถป้องกันการเขียนได้เนื่องจากมีกระบวนการที่เขียนไปยังโฟลเดอร์นี้อย่างต่อเนื่อง มีวิธีที่ดีกว่าที่จะทำหรือไม่


2
คุณลองใช้ alias rmto rm -i:> -i prompt ก่อนทุกการลบหรือ> -I prompt หนึ่งครั้งก่อนลบไฟล์มากกว่าสามไฟล์หรือเมื่อลบซ้ำ รบกวนน้อยกว่า -i ในขณะที่ยังคงป้องกันความผิดพลาดส่วนใหญ่คุณสามารถเขียนสิ่งที่มีค่าสถานะอื่นได้ตลอดเวลา
IBr

2
ลองดูsafe-rm
sr_

มีหลายวิธีที่จะทำ คุณจะต้องลงรายละเอียดเพิ่มเติมเกี่ยวกับสภาพแวดล้อมของคุณ
Ignacio Vazquez-Abrams


อีกแนวคิดหนึ่งคือการใช้นามแฝงเป็นฟังก์ชันที่เพิ่งย้ายไปยังโฟลเดอร์เฉพาะแล้วสร้าง cronjob ที่ทำงานtmpwatchเพื่อลบไฟล์ออกจากโฟลเดอร์นี้ทุกชั่วโมง
Bratchley

คำตอบ:


14

ในการค้นคว้าคำถามของคุณฉันพบเทคนิคนี้ซึ่งอาจช่วยคุณในอนาคต

เห็นได้ชัดว่าคุณสามารถสัมผัสไฟล์ในไดเรกทอรีดังนี้:

touch -- -i

ตอนนี้เมื่อคุณเรียกใช้คำสั่งrm -fr *ในไดเรกทอรีที่มีอยู่ที่คุณจะนำเสนอกับการโต้ตอบรวดเร็วจาก-irm

$ ls
file1  file2  file3  file4  file5  -i

$ rm -fr *
rm: remove regular empty file `file1'? n
rm: remove regular empty file `file2'? n
rm: remove regular empty file `file3'? n
rm: remove regular empty file `file4'? n
rm: remove regular empty file `file5'? n

สิ่งเดียวที่สามารถทำได้โดยเพียงแค่ออกจากนามแฝงในสถานที่สำหรับการมักจะทำrm rm -iสิ่งนี้อาจทำให้เกิดความรำคาญ บ่อยครั้งที่สิ่งที่ฉันได้เห็นก็คือให้มีนามแฝงนี้เข้ามาแล้วปิดใช้งานเมื่อคุณต้องการลบโดยไม่ได้รับแจ้ง

alias rm='rm -i'

ตอนนี้ในไดเรกทอรีคุณจะได้รับการต้อนรับเช่นนี้:

$ ls
file1  file2  file3  file4  file5

$ rm -r *
rm: remove regular empty file `file1'?

หากต้องการแทนที่นามแฝง:

$ \rm -r *

ยังคงไม่หยุดrm -frอย่างไรก็ตาม แต่มันให้ความคุ้มครองแก่คุณบ้าง

อ้างอิง


1
นี่เป็นโซลูชันที่สวยงามและสวยงามซึ่งทำงานได้ดีหากคุณต้องการ / ต้องการปกป้องไดเรกทอรีขนาดเล็ก และฉันอาจจะล้าสมัย แต่ฉันก็ยังมีชีวิตอยู่ภายใต้ความประทับใจที่ถ้าคุณพูด--forceกับบางสิ่งคุณหมายถึงมันจริงๆ
CVn

นอกจากนี้โปรดทราบว่าrm -I(ตัวพิมพ์ใหญ่i) อาจมีประโยชน์ในนามแฝงเนื่องจากมีการก้าวก่ายน้อยกว่าเล็กน้อย (ตามหน้า man จะแจ้งให้เฉพาะเมื่อคุณลบไฟล์มากกว่าสามไฟล์หรือเรียกซ้ำ)
CVn

โปรดทราบว่าtouch ./-iเทคนิคนี้ใช้ได้กับ GNU rmเท่านั้นและหากตัวแปร POSIXLY_CORRECT ไม่ได้ตั้งค่าไว้ (คำสั่ง POSIX จะไม่รู้จักตัวเลือกหลังจากอาร์กิวเมนต์)
Stéphane Chazelas

5

ความเป็นไปได้มากมาย:

  • alias rm='rm -i'- rm จะถาม - เว้นแต่คุณจะระบุ-f...
  • chmod -w dir - ปกป้องไฟล์โดยตรงในไดเรกทอรีนั้น
  • chattr +i ถ้าคุณหมายถึงมันจริงๆ
  • เขียนเสื้อคลุมของคุณเองรอบ ๆ RM
  • ฯลฯ ...

แต่วิธีที่ดีกว่าน่าจะมีการสำรองข้อมูลที่ดีและเก็บข้อมูลสำคัญไว้ในการควบคุมเวอร์ชัน (เช่นgit) ซึ่งนำข้อดีอื่น ๆ มาใช้เช่นกัน


1
มาที่นี่เพื่อพูดถึงเรื่องนี้ ฉันจะแนะนำ chattr + i เพื่อให้ปลอดภัยโดยสิ้นเชิง
JZeolla

ฉันได้ใช้นามแฝงของอาร์เอ็มเอสแล้วrm -iแต่อย่างใดอย่างหนึ่งคาดว่าจะไม่ทำงานกับ-fตัวเลือก ฉันใช้ git เพื่อจุดประสงค์อื่น ๆ แต่ถ้าฉันทำrm -rf *git โดยไม่ตั้งใจด้วยล่ะ
Dilawar

ด้วย git หากคุณลบเพียงไดเรกทอรีย่อยคุณสามารถเรียกคืนได้อย่างง่ายดายจากที่เก็บในเครื่องของคุณ หากคุณลบที่เก็บข้อมูลทั้งหมดคุณสามารถทำการโคลนอีกครั้งได้เนื่องจากคุณได้ผลักมันไปยังที่อื่นก่อน
Michas

1

ใช้ซอฟต์แวร์ควบคุมเวอร์ชันเช่นgitทำแค็ปซูลโครงการของคุณ

ตราบใดที่คุณไม่ลบโครงการทั้งหมดคุณจะต้องพิมพ์อย่างตั้งใจrm -rf .*เพื่อลบ.gitไดเรกทอรีและสูญเสียข้อมูลทั้งหมดที่จำเป็นสำหรับการย้อนกลับ

สิ่งนี้มีประโยชน์เพิ่มเติมที่คุณสามารถผลักดันการสำรองข้อมูลของคุณไปยังเซิร์ฟเวอร์ระยะไกลเช่น github หรือ bitbucket


1

นี่คือวิธีการrm -rf dirทำงาน:

  1. มันเปิดขึ้นdirและแสดงรายการเนื้อหา
  2. สำหรับแต่ละรายการถ้าเป็นไดเรคทอรีให้ทำซ้ำกระบวนการเดียวกันหากไม่มีให้เรียกunlinkใช้

หากคุณทำได้ให้ส่งคืนชื่อไฟล์พิเศษก่อนและถ้าคุณสามารถทำให้กระบวนการทำunlinkไฟล์นั้นตายได้นั่นจะช่วยแก้ปัญหาได้ สามารถทำได้โดยใช้ระบบไฟล์ฟิวส์

ตัวอย่างเช่นคุณสามารถปรับloopback.plตัวอย่างจากโมดูล perl Fuseซึ่งเพิ่งใช้ระบบไฟล์จำลองที่เป็นเพียงการส่งผ่านไปยังระบบไฟล์จริงที่อยู่ด้านล่าง (เช่นดูแพทช์ด้านล่าง):

  • เมื่อมีการระบุรายชื่อไดเรกทอรีหากมีรายการที่มีชื่อ.{{do-not-delete}}.ให้เพิ่มรายการรายการที่มีสองไฟล์: .{{do-not-delete}}!errorและ.{{do-not-delete}}!kill
  • เมื่อลองรหัสunlinkแรกให้ส่งคืนEPERMรหัสเพื่อrmแสดงข้อความแสดงข้อผิดพลาด
  • เมื่อพยายามunlinkที่สองกระบวนการถูกฆ่าตาย

$ ls -Ff dir/test
./  .{{do-not-delete}}.  foo/  ../  bar
$ ./rm-rf-killer dir
$ ls -Ff dir/test
.{{do-not-delete}}!error  .{{do-not-delete}}!kill  ./  .{{do-not-delete}}.   foo/  ../  bar
$ rm -rf dir/test
rm: cannot remove `dir/test/.{{do-not-delete}}!error': Operation not permitted
zsh: terminated  rm -rf dir/test
$ ls -Ff dir/test
.{{do-not-delete}}!error  .{{do-not-delete}}!kill  ./  .{{do-not-delete}}.   foo/  ../  bar

นี่คือแพทช์ที่ใช้บนloopback.plตัวอย่างนั้นเป็นข้อพิสูจน์แนวคิด:

--- loopback.pl 2013-06-03 22:35:00.577316063 +0100
+++ rm-rf-killer    2013-06-03 22:33:41.523328427 +0100
@@ -7,2 +7,4 @@
 my $has_threads = 0;
+my $flag = ".{{do-not-delete}}";
+
 eval {
@@ -42,3 +44,4 @@

-use blib;
+#use blib;
+use File::Basename;
 use Fuse;
@@ -49,3 +52,3 @@

-my %extraopts = ( 'threaded' => 0, 'debug' => 0 );
+my %extraopts = ( 'threaded' => 0, 'debug' => 0, 'mountopts' => 'nonempty' );
 my($use_real_statfs, $pidfile);
@@ -64,3 +67,7 @@

-sub fixup { return "/tmp/fusetest-" . $ENV{LOGNAME} . shift }
+sub fixup {
+    my $f = shift;
+    $f =~ s#(/\Q$flag\E)!(error|kill)$#$1.#s;
+    return ".$f";
+}

@@ -78,3 +85,9 @@
 }
-    my (@files) = readdir(DIRHANDLE);
+    my @files;
+    
+    while (my $f = readdir(DIRHANDLE)) {
+        unshift @files, "$flag!error", "$flag!kill"
+            if ($f eq "$flag.");
+        push @files, $f;
+    }
 closedir(DIRHANDLE);
@@ -121,3 +134,12 @@
 sub x_readlink { return readlink(fixup(shift));         }
-sub x_unlink   { return unlink(fixup(shift)) ? 0 : -$!; }
+sub x_unlink   {
+    my $f = shift;
+    if (basename($f) eq "$flag!error") {return -EPERM()}
+    if (basename($f) eq "$flag!kill") {
+        my $caller_pid = Fuse::fuse_get_context()->{"pid"};
+        kill("TERM", $caller_pid);
+        return -EPERM();
+    }
+    return unlink(".$f") ? 0 : -$!;
+}

@@ -203,3 +225,2 @@
 sub daemonize {
-    chdir("/") || die "can't chdir to /: $!";
 open(STDIN, "< /dev/null") || die "can't read /dev/null: $!";
@@ -236,2 +257,3 @@

+chdir($mountpoint) or die("chdir: $!");
 daemonize();
@@ -239,3 +261,3 @@
 Fuse::main(
-    'mountpoint'    => $mountpoint,
+    'mountpoint'    => '.',
 'getattr'       => 'main::x_getattr',

-1

ฉันได้สร้างสคริปต์เพื่อทำให้งานนี้ง่ายขึ้น เชลล์สคริปต์ปรับเปลี่ยนสิทธิ์การอ่าน / เขียนและการตั้งค่าสถานะ chattr ของรายการโฟลเดอร์ที่กำหนดไว้แบบโต้ตอบโดยไม่ต้องถามรหัสผ่านรูท คุณสามารถดาวน์โหลดไฟล์ zip ได้จากลิงค์ด้านล่าง

https://drive.google.com/file/d/0B_3UYBZy2FVsMVpBSWdSWnFBYk0/edit?usp=sharing

ฉันได้รวมสคริปต์การติดตั้งเพื่อให้การตั้งค่าง่ายขึ้น คำแนะนำอยู่ในไฟล์ zip

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.