배열에 저장된 여러 디렉터리를 지우려고 합니다. 다음은 간단한 예입니다(더 많은 디렉토리가 있습니다).
#!/bin/bash
$IMAGES_DIR="/Users/michael/scripts/imagefiles"
$BACKUP_DIR="/Users/michael/scripts/imagebackups"
...
array=( $IMAGES_DIR $BACKUP_DIR )
for i in ${array[@]}
do
if [ "$(ls -A $i)" ]; then # check that directory has files in it
rm "$i/"* # remove them
fi
done
각 디렉토리에 대해 다음과 같은 오류가 발생합니다.
rm: /Users/michael/scripts/imagefiles/*: 해당 파일이나 디렉터리가 없습니다.
답변1
하나의 명령으로 모든 것을 수행하는 것은 어떻습니까?
단일 호출로 파일 존재 확인, 글로빙, 삭제를 캡처할 수 있습니다 find
. GNU 버전의 경우 find
다음이 있습니다.
for f in "${array[@]}"; do
find "$f" -type f -delete
done
GNU가 없으면 find
다음 호출을 사용하십시오.
find "$f" -type f -exec rm -f {} +
( 전체 디렉토리 계층에서 파일을 지우지 않고 직접 하위 파일만 지우려면 -maxdepth 1
앞에 추가하십시오 -type f
.)
하지만 잠깐만요, 더 있습니다…
~처럼John1024는 현명하게 지적합니다.배열을 첫 번째 인수로 전달하여 루프를 완전히 중단할 수 있습니다 find
.
find "${array[@]}" -type f -delete
그 이유는 다음과 같습니다.1) find
한 번의 실행으로 여러 디렉터리를 검색하고 처리할 수 있습니다.2)쉘은 각 요소(디렉토리)가 별도의 위치 인수가 되도록 배열을 분할합니다 find
.
답변2
코드를 다음과 같이 변경하세요.
#!/bin/bash
IMAGES_DIR="/Users/michael/scripts/imagefiles"
BACKUP_DIR="/Users/michael/scripts/imagebackups"
array=( $IMAGES_DIR $BACKUP_DIR )
for i in "${array[@]}"
do
if [ "$(ls -A "$i")" ]; then
rm "${i:?}"/*
fi
done
실수:
$
변수 할당 왼쪽에 배치$i
인용 되지 않음if [ "$(ls -A $i)" ];then
"${var:?}"
이를 보장하는 데 사용되며rm "$i/"*
절대로 확장되지 않습니다./*
답변3
옵션을 사용하면 파일 피연산자가 존재하지 않는 경우 유틸리티가 불평하지 않습니다 -f
. rm
또한 실패 시 종료되지 않습니다.
무엇인가요가능한귀하의 경우에는 숨겨진 이름이 있는 파일이나 디렉터리를 제외하고 하나 이상의 디렉터리가 비어 있으므로 *
패턴 끝에 있는 디렉터리는 아무 것도 확장되지 않습니다. 쉘 옵션을 설정하여 *
glob이 숨겨진 이름과 일치하도록 할 수 있습니다.bash
dotglob
또한 할당에 변수 이름을 사용해서는 안 되며 $
토큰화 및 파일 이름 생성(와일드카드)을 방지하려면 큰따옴표 변수 확장이 필요합니다. 실수로 환경 변수나 특수 쉘 변수를 손상시키지 않도록 변수 이름은 소문자여야 합니다.
이러한 요소를 고려한 대체 코드 공식화;
#!/bin/bash
shopt -s dotglob
images_dir="/Users/michael/scripts/imagefiles"
backup_dir="/Users/michael/scripts/imagebackups"
dirs=( "$images_dir" "$backup_dir" )
for dir in "${dirs[@]}"; do
rm -f "$dir"/*
done
위의 코드는 디렉터리에서 모든 파일을 삭제하려고 시도합니다. 디렉터리에 하위 디렉터리가 있으면 rm
이와 관련된 오류가 발생합니다. 이들도 제거하려면 -r
with 를 사용하십시오 rm
.
답변4
rm
목표가 폴더 배열의 모든 파일을 삭제하는 것이라면 또 다른 옵션은 다음과 같이 배열을 전달하는 것입니다.
#!/bin/bash
$IMAGES_DIR="/Users/michael/scripts/imagefiles"
$BACKUP_DIR="/Users/michael/scripts/imagebackups"
# ...
# to preserve whitespaces in path strings, add double quotes around each variable
array=( "$IMAGES_DIR" "$BACKUP_DIR" )
# this appends "/*" to the end of each dirname if you want to delete the contents of the directories
# without deleting the directories themselves
array=( "${array[@]/%//*}" )
# this will spread the array into multiple calls to rm
rm -rf ${array[@]}
한 줄의 예:
rm -rf ${array[@]/%//*}
그러나 폴더도 삭제하려면 다음을 사용할 수 있습니다.
rm -rf ${array[@]}
주목해야 할 차이점B층 용액, while은 find
제공된 경로를 찾는 동안 발생하는 모든 오류를 인쇄 rm
하지만 이 경우에는 그렇지 않습니다.
편집하다:
~처럼선행경로에 공백이나 쉘 와일드카드가 있으면 이와 같이 배열을 확장하는 것이 위험할 수 있다는 점에 유의하는 것이 중요합니다. 이러한 문자로 인해 배열이 분할되는 것을 방지하려면 배열에 추가하는 변수 주위에 큰따옴표를 추가해야 합니다.