저는 bash 스크립팅을 처음 접했고 아직 초안이지만 이 스크립트는 예상대로 작동했습니다.
#!/bin/bash
find /var/www/site.com/ -type f -name "*.log" | xargs bash -c '
for name; do
parent=${name%/*}
parent=${parent##*/}
destdir=$(dirname $name)
current_year=$(date +"%Y")
if [[ "$name" =~ _([0-9]{4})- ]] &&
[[ "$name" != *"$current_year"* ]]; then
year="${BASH_REMATCH[1]}"
else continue
fi
if [ ! -d "$destdir/$year/$parent" ]; then
mkdir -p "$destdir/$year/"
fi
mv "$name" "$destdir/$year"
done '
find /var/www/site.com/ -type d -name "20*" | xargs bash -c '
for dir; do
tar_name=$(echo $dir | grep -Eo '[0-9]{4}')
tar cvfj '$tar_name'.tbz $dir
done '
exit
보시다시피 bash 스크립트에서 bash를 두 번 호출했습니다. 이것은 나쁜 습관입니까? 말이 안 되나요/말이 안 되나요? 아니면 find 명령의 출력을 사용하여 배열을 만들고 반복하는 것이 더 낫습니까? 어떤 조언이라도 대단히 감사하겠습니다. 미리 감사드립니다. PS 들여쓰기가 부족해서 죄송합니다
답변1
내부 쉘 스크립트를 보지 않고도 몇 가지 참고할 사항이 있습니다.
파일 이름에 공백, 따옴표 또는 백슬래시 문자가 포함되어 있으면 일반 xargs
작업이 실패합니다 . 여기에는 대부분의 다른 인용 규칙과 호환되지 않는 자체 인용 규칙 세트가 있습니다. (지금은 참고 질문을 찾을 수 없습니다.)
인라인 쉘 스크립트에 "0번째" 인수가 누락되어 첫 번째 파일 이름을 건너뛰게 됩니다.
또한 구문 강조 표시는 두 번째 명령이 깨졌음을 보여줍니다. grep -Eo '[0-9]{4}'
전체 스크립트 주위에 작은 따옴표를 닫았다가 다시 여는 따옴표가 있습니다.
이제 이 문제는 xargs
쉽게 해결되었으며 find ... -print0 | xargs -0 command...
많은 구현(GNU, FreeBSD, Busybox)에서 이를 지원합니다.
0번째 매개변수 문제를 해결하려면 더미 매개변수( 로 끝나는 $0
)를 추가해야 합니다.
... | xargs -0 bash -c '...' sh
또는 find ... -exec bash -c '...' sh {} +
.
그러나 다른 쉘을 시작하지 않는 것이 좋습니다. Bash에서는 다음을 수행할 수 있습니다.
find ... -print0 | while IFS= read -r -d '' file; do
something with "$file"
done
또는,
while IFS= read -r -d '' file; do
something with "$file"
done < <(find ... -print0)
후자는 루프 내부에 변수를 설정하고 루프 외부에서 변수를 사용할 수 있을 것으로 예상되는 경우에도 작동합니다.
관련 섹션 보기찾기 결과를 반복하는 것이 왜 나쁜 습관입니까?(명령 대체를 사용하지 않으므로 모든 것이 관련이 있는 것은 아닙니다.)
출력을 find
배열에 넣으려면 다음을 사용하십시오.
mapfile -t -d '' array < <(find ... -print0)
답변2
bash가 ≥4.3이라고 가정하면 호출 대신 재귀 와일드카드를 사용할 수 있습니다 find
. find
호출에는 아무런 문제가 없지만(올바르게 수행한 경우: 아래 참조) 재귀 와일드카드가 작동할 때는 덜 편리합니다. 전화해야 해shopt -s globstar
재귀적 와일드카드를 활성화합니다.
shopt -s globstar
for name in /var/www/site.com/**/*.log; do
…
done
for dir in /var/www/site.com/**/20*/; do
…
done
하나를 사용하는 경우 파이프 로 find
연결하지 마십시오 . 파일 이름을 구분하기 위해 다른 구문을 사용하므로 이름에 공백이 포함되어 있으면 셸 호출을 사용 하거나 .find
xargs
\'"
-exec
find … -print0 | xargs -0
공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까?더 많은 정보를 알고 싶습니다.