때로는 디렉토리의 모든 내용을 삭제하고 거기에 새 파일을 만들어야 할 때가 있습니다. 다음과 같은 작업을 수행하고 모든 새 파일이 변경되지 않은 상태로 유지되기를 기대할 수 있습니다.
% rm -rf regression/* & ( sleep 10 ; run_regression )
run_regression
고유한 이름을 갖도록 출력 파일에 타임스탬프를 어디에 추가하고 에 배치합니까 regression
?
내 생각에는 쉘이 regression/*
명시적인 목록으로 구문 분석될 것이라고 생각합니다.기존의filename을 선택하면 rm
해당 명시적 목록에 있는 파일은 삭제되지만 run_regression
.filename과 동시에 생성된 새 파일은 삭제되지 않습니다 rm
. 해당 파일에는 타임스탬프가 지정되어 있으므로 run_regression
이름 충돌이 없어야 합니다.
그러나 쉘이 파일 목록을 완료하고 작업을 시작한 시기를 어떻게 알 수 있는지 잘 모르겠습니다 rm
. 위의 10초면 충분합니까? 다음과 같이 할 수 있습니까 bash
?
% rm -rf regression/* & ( wait_unil_names_are_resolved ; run_regression )
설명에서 명확히 하기 위해 쉘에 익숙한 도구인 경우에도 도구를 호출하기 전에 와일드카드가 파일 이름으로 확장되도록 보장하는지 여부를 쉘에 실제로 묻고 있습니다. 쉘 및 도구 개발자가 파이프 와일드카드 확장을 위해 도구를 사용하고 싶은 유혹을 느낄 수도 있습니다. 이러한 일이 발생하지 않도록 하는 표준이 있었으면 좋겠습니다.
답변1
명령이 작동할 수도 있지만 테스트 사례는 다음과 같습니다.
$ ls
$ echo * $(sleep 1)&touch file1
[1] 12798
$ file1
[1]+ Done echo * $(sleep 1)
file1은 입력이 아니며 echo 명령의 출력입니다.
편집하다:
또 다른 테스트 실행:
$ ls
$ touch file1
$ for i in {1..5000}; do rm * & touch file$i; wait;done|grep file
rm: cannot remove '*': No such file or directory
***previous line repeated 14 times***
답변2
이것은 안전하지 않습니다.
해결하려는 문제가 무엇인지 지정하지 않았습니다. 문제가 디렉토리가 항상 존재하지만 때때로 정리되기를 원하는 경우, 확인된 파일보다 오래된 파일을 명시적으로 삭제하는 것이 좋습니다(sleep 1은 제가 편집증적인 부분입니다).
touch regression.delete \
&& find regression \! -newer regression.delete -delete & \
&& sleep 1 \
&& run_regression
하위 디렉토리가 있으면 문제가 발생합니다. 대신 쓸 수 있습니다.
touch regression.delete \
&& find regression -mindepth 1 -maxdepth 1 \! -newer regression.delete -exec rm -rf '{}' \; & \
&& sleep 1 \
&& run_regression
문제가 가능한 한 빨리 프로그램을 시작하고 싶은 경우, 디렉토리가 일시적으로 존재하지 않고 마운트 지점이 아닌 경우 일반적으로 다음과 같은 명령을 실행합니다.
mkdir regression.new \
&& chmod --reference regression regression.new \
&& mv regression regression.delete \
&& mv regression.new regression \
&& rm -rf regression.delete & \
run_regression
이렇게 하면 run_regression을 거의 즉시 시작할 수 있습니다.
편집 내용에 응답하고(다른 답변의 연구를 기반으로 내 자신을 편집) rm
명령을 시작하기 전에 와일드카드를 확장해야 하지만 문제의 요점은 쉘 포크 후에 확장이 수행되는지 여부를 아는 것입니다.비동기 실행을 위한 POSIX 사양내가 아는 한, 어떤 식으로든 명시적인 사양은 없습니다. 섹션 2.1은 확실히 확장이 다른 작업이고 명령의 실제 포크/실행보다 선행하지만 테스트(@adonis에 의해, 제가 bash 4.3을 사용하여)를 암시합니다( 복사됨) .42(1))은 bash가 가장 효율적인 접근 방식을 취한다고 제안합니다. 와일드카드 확장에 시간이 걸리는 경우 다음 명령으로 수행한 수정 사항이 해당 확장에 영향을 미칠 수 있습니다. 따라서 처음에는 삭제하고 싶지 않은 파일을 삭제하려고 생각할 수도 있습니다.
bash 소스 코드를 살펴본 다음실행_cmd.c단어 확장 전에 포크가 수행된다는 점을 분명히 하십시오.
3922 | /* If we're in a pipeline or run in the background, set DOFORK so we
3923 | make the child early, before word expansion. This keeps assignment
3924 | statements from affecting the parent shell's environment when they
3925 | should not. */
답변3
rm -rf regression/*
달리다평행하게그리고 ( sleep 10 ; run_regression )
. 이는 사물의 순서를 보장할 수 없음을 의미합니다. rm -rf regression/*
먼저 디렉터리에 있는 파일 목록을 수집 regression
한 다음 호출하여 rm
삭제합니다. 이는 진공 상태에서 발생하지 않으며 명령을 평가하는 동안 셸에서 수행되는 작업 rm -rf regression/*
이며 연산자로 인한 포크 후에 발생합니다 &
. 수집 단계가 10초 미만이면 생성된 파일은 run_regression
안전합니다. 에서 생성한 파일에 도달하는 데 수집 단계가 10초 이상 소요되면 run_regression
해당 파일이 삭제됩니다.
파일을 삭제해도 run_regression
파일을 닫았다가 다시 열지 않으면 실제로 아무런 효과가 없습니다. 파일을 삭제해도 해당 파일을 연 프로세스에는 영향을 미치지 않습니다. 해당 파일을 연 모든 프로세스가 해당 파일을 닫을 때까지 파일은 디렉터리 항목 없이 그대로 유지됩니다(즉, 하드 링크 개수는 0입니다). 하지만 프로그램의 출력은 삭제되므로 해당 출력에 액세스할 수 없습니다.
그러니 하지 마세요. 타이밍에 의존하지 마십시오. 대기 시간이 10초만큼 높으면 테스트 중에 작동합니다(특히 테스트 중에 파일 수가 적고, 핫 캐시가 없고, I/O 스파이크가 없고, 시스템 일시 중지가 없을 수 있으므로). 테스트 중) 그러나 조만간 프로덕션에서는 실패할 것입니다.
디렉토리를 유지하고 그 안의 파일을 삭제하려면 먼저 파일 이름 수집을 수행하십시오.
files_to_delete=(regression/*)
rm -rf "${files_to_delete[@]}" & run_regression
(배열이 있는 쉘을 가정합니다. 일반 sh에서는 를 사용합니다 set regression/*; rm -rf "$@" & run_regression
.) 물론 이는 이러한 파일이 run_regression
존재하지 않는 파일만 생성한다고 가정하고 기존 파일을 덮어쓰면 해당 파일이 삭제됩니다.
아마도 이 모든 복잡성이 필요하지 않을 것입니다. 그냥 실행하십시오.
rm -rf regression/*
run_regression
파일 목록이 너무 커서 캐시에 맞지 않거나 파일 시스템이 쓰기 작업에 비해 비정상적으로 느린 경우를 제외하고 이름 목록을 수집하는 것은 삭제하는 것보다 시간이 더 오래 걸리므로 성능에 영향을 주지 않습니다.
삭제 작업의 성능이 정말 좋지 않은 경우(이 역시 특이한 경우) 새 디렉터리를 만듭니다.
mv regression regression.old
mkdir regression
rm -rf regression.old &
run_regression
답변4
새 파일 이름을 사용하는 것이 안전합니다. 쉘은 inode 등이 아닌 파일 이름을 알고 명령을 실행하기 전에 와일드카드(와일드카드 확장)를 수행합니다. ~에 따르면POSIX:
2.6.6 경로명 확장
필드 분할 후
set -f
적용되지 않는 경우 생성된 명령줄의 각 필드는 다음에 설명된 알고리즘을 사용하여 확장되어야 합니다.패턴 일치 표기법,규칙을 준수한다파일 이름 확장에 사용되는 패턴.
즉, 이는 명령이 실제로 실행되기 전에 발생하는 구문 분석의 잘 정의된 단계입니다. POSIX에서 가장 복잡한 경우가 처리됩니다.리디렉션그리고작업. 이 예에는 아무것도 없으므로 적용되는 내용은 다음과 같습니다.
- 변수 할당이나 리디렉션이 아닌 단어는 확장되어야 합니다. 확장 후 남은 필드가 있는 경우 첫 번째 필드는 명령 이름으로 처리되어야 하며 나머지 필드는 명령에 대한 인수입니다.
질문에 표시된 예에서는 디렉터리를 삭제하지 않는 것으로 보입니다. 삭제되었을 수 있는 하위 디렉터리의 존재에 의존하는 경우에도 동일한 경고가 적용됩니다.
아마도 귀하의 타임스탬프(10초예차이점은두번째타임스탬프)는 결과 파일 이름의 일부가 됩니다.