'rm -rf'로부터 보호 된 디렉토리 만들기


9

방금 폴더 B 안에 있던 폴더 A의 일부 데이터를 잃어 버렸습니다 rm -rf B. 내가 한 일을 깨닫기 전에 모든 것이 끝났습니다. 이제 교훈을 배웁니다. 다음에 비슷한 것을하고 자신을 죽이고 싶을 때 내 폴더를 바보로 만들지 않기를 바랍니다.

내가 생각할 수있는 한 가지 방법은 bash 함수를 작성하고에 별칭을 지정하는 것 rm입니다. 이 기능은 각 하위 폴더에서와 같은 숨겨진 파일을 찾습니다 .dontdelete. 발견되면 실제로 계속하고 싶은지 묻습니다. 이 폴더에 지속적으로 쓰는 프로세스가 있기 때문에 쓰기 금지되어 있습니다. 더 좋은 방법이 있습니까?


2
제거 할 때마다> -i 프롬프트 또는 세 개 이상의 파일을 제거하기 전에> -I 프롬프트를 한 번 또는 재귀 적으로 제거 할 때 별칭 rm을 시도 했습니까? rm -i대부분의 실수에 대한 보호 기능을 제공하면서 -i보다 방해가 적습니다. 언제든지 다른 플래그를 사용하여 실수를 기록 할 수 있습니다.
IBr

2
체크 아웃safe-rm
sr_

그것을하는 방법은 약 12 ​​가지가 있습니다. 환경과 관련하여 더 자세히 설명해야합니다.
Ignacio Vazquez-Abrams


또 다른 아이디어는 특정 폴더로 옮기고 tmpwatch매 시간 마다이 폴더에서 파일을 삭제 하는 cronjob을 만드는 함수로 별칭을 지정하는 것입니다 .
Bratchley 2016 년

답변:


14

귀하의 질문을 조사 할 때 앞으로 도움이 될 수있는이 기술을 발견했습니다.

디렉토리의 파일을 다음과 같이 만질 수 있습니다.

touch -- -i

이제 rm -fr *디렉토리가있는 디렉토리에서 명령을 실행하면 -i에서 대화식 프롬프트가 표시됩니다 rm.

$ 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 페이지에 따르면 3 개 이상의 파일을 제거하거나 재귀 적으로 표시하는 경우에만 프롬프트가 표시됨).
CVn

touch ./-i트릭 rm은 POSIXLY_CORRECT 변수가 설정되지 않은 경우에만 GNU에서만 작동합니다 (POSIX 명령은 인수 뒤에 옵션을 인식하지 못합니다).
Stéphane Chazelas

5

많은 가능성 :

  • alias rm='rm -i'-rm이 묻습니다-지정하지 않으면 -f...
  • chmod -w dir -해당 디렉토리에있는 파일을 직접 보호합니다.
  • chattr +i 당신이 정말로 그것을 의미한다면
  • rm 주위에 자신의 래퍼를 작성
  • 기타...

그러나 더 좋은 방법은 좋은 백업을하고 중요한 데이터를 (예 :와 같은 git) 버전 관리 방식으로 유지하는 것입니다 . 이로 인해 다른 많은 이점도 있습니다.


1
이것을 언급하기 위해 여기에 왔습니다. chattr + i가 완전히 안전하도록 제안합니다.
JZeolla 2016 년

나는 이미 별칭을 가지고 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해당 파일에서 수행중인 프로세스가 종료 될 수 있으면 문제가 해결됩니다. 퓨즈 파일 시스템을 사용하여 수행 할 수 있습니다.

예를 들어, 아래의 실제 파일 시스템으로 전달되는 더미 파일 시스템을 구현하는 perl Fuse 모듈loopback.pl예제 를 조정할 수 있습니다 (아래 패치 참조).

  • 디렉토리를 나열 할 때 그것이라는 항목이 포함 된 경우, .{{do-not-delete}}.두 개의 파일이있는 항목의 목록을 앞에 추가 : .{{do-not-delete}}!error.{{do-not-delete}}!kill
  • unlink첫 번째 시도 할 때 오류 메시지 EPERMrm표시 되도록 코드를 반환하십시오.
  • 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.