
7일이 지난 파일을 삭제하기 위해 찾기 결과를 배열로 배포하기 위해 다음 명령을 작성했습니다.
F_ARR[0]=''
unset F_ARR
find "$CDIR" ! -type d -mtime +7 -exec sh -c '
for pathname; do
F_ARR+=("$pathname")
done' sh {} +
echo ${#F_ARR[@]}
그러나 F_ARR 배열의 길이를 인쇄하면 0이 표시됩니다. 내 코드에 실수가 있었나요?
답변1
find ... -exec sh -c 'sh code' {} +
bash/ksh 셸에서 find
하나 이상의 명령 호출을 실행하는 새 프로세스에서 명령을 실행합니다. 이 코드를 해석하는 호출의 변수에만 영향을 미칠 sh
수 있습니다 (단, 배열 지원을 의미하지는 않습니다).sh code
sh
sh
찾은 파일의 경로를 현재 쉘의 배열에 저장하려면 find
해당 쉘에서 할당을 수행해야 합니다.
4.4+ 에서는 bash
다음을 수행할 수 있습니다.
readarray -td '' F_ARR < <(find "$CDIR" ! -type d -mtime +7 -print0)
find
지원하지 않는 경우 -print0
로 대체할 수 있습니다 -exec printf '%s\0' {} +
.
(이전 버전의 경우 bash
다음을 참조하세요.비슷한 질문에 대한 답변에서 이를 수행하는 방법은 무엇입니까?).
zsh
여기에서는 대신 셸을 사용할 수도 있습니다 .
f_arr=($CDIR/**/*(NDm+7^/))
위와 차이점은 다음과 같습니다.
- 파일 목록이 정렬되었습니다.
oN
glob 한정자를 추가하여 정렬을 비활성화 할 수 있습니다. $CDIR
8일이 넘은 경우에도 자체적으로 포함되지 않습니다.$CDIR
디렉토리에 대한 심볼릭 링크인 경우zsh
에도 해당 디렉토리로 이동합니다.
질문에 및 으로 태그를 지정했으므로 bash
ksh 의 다양한 구현 및 변형 또는ksh
(ksh88, ksh93, David Korn의 향후 ksh2020(원래), pdksh 및 그 파생물(예: OpenBSDsh
mksh
대부분의 기능은 및 bash
에서 제공되며 일부 기능은 및 에서 제공됩니다 . 기본 기능이며 다른 곳에서는 찾을 수 없는 몇 가지 기능 중 하나입니다 .ksh88
ksh93
zsh
mksh
readarray
bash
-d
ksh93은 나중에 bash(2000), zsh(2003) 및 mksh(2011)에 의해 복사된 옵션 을 1993년에 read
추가했지만 bash, zsh, mksh 및 ksh2020만 null 구분 기호와 함께 이를 사용하여 NUL로 구분된 레코드를 처리할 수 있습니다. 프로세스 대체는 ksh86(1986)에 추가되었지만 pdksh 기반 ksh 변형 중 어느 것도 이를 지원하지 않으므로 위에서 이전 버전에 대해 언급한 방법은 bash
모든 ksh 버전에서 작동하지 않습니다(zsh의 ksh 에뮬레이션 모드 제외).
ksh88, ksh93 및 pdksh 기반 셸에서 한 가지 옵션은 출력을 사후 처리하여 find
배열을 정의하고 다음을 사용하여 코드를 평가할 수 있는 셸 코드를 생성하는 것입니다 eval
.
eval set -A F_ARR "$(
LC_ALL=C find "$CDIR" ! -type d -exec awk -v q="'" -- '
BEGIN {
for (i = 1; i < ARGC; i++) {
gsub(q, q "\\" q q, ARGV[i])
printf " %s", q ARGV[i] q
}
exit
}' {} +
)"
(이것은 또는 $CDIR
로 시작하지 않는다고 가정합니다 . 가능하다면 일부 구현에서는 를 사용할 수 있습니다 . 어쨌든 로 시작하면 차단 됩니다).+
-
ksh
set -A F_ARR --
-
find
set -A F_ARR
모든 POSIX sh에 동일한 접근 방식을 사용할 수 있으며 다음 을 대체하여 set --
POSIX 셸용 배열을 채울 수 있습니다 "$@"
.
답변2
이것은 예상된 것입니다 - 참조맨페이지All commands of a pipeline are executed in separate subshells
이 인용문 및 다음 FAQ 항목 과 같은 자세한 내용을 보려면 다음을 참조하세요 .
Something is going wrong with my while...read loop
Most likely, you've encountered the problem in which the shell runs all
parts of a pipeline as subshell. The inner loop will be executed in a
subshell and variable changes cannot be propagated if run in a pipeline:
bar | baz | while read foo; do ...; done
Note that exit in the inner loop will only exit the subshell and not the
original shell. Likewise, if the code is inside a function, return in
the inner loop will only exit the subshell and won't terminate the func‐
tion.
Use co-processes instead:
bar | baz |&
while read -p foo; do ...; done
exec 3>&p; exec 3>&-
If read is run in a loop such as while read foo; do ...; done then lead‐
ing whitespace will be removed (IFS) and backslashes processed. You
might want to use while IFS= read -r foo; do ...; done for pristine I/O.
Similarly, when using the -a option, use of the -r option might be pru‐
dent (“read -raN-1 arr <file”); the same applies for NUL-terminated
lines:
find . -type f -print0 |& \
while IFS= read -d '' -pr filename; do
print -r -- "found <${filename#./}>"
done
따라서 코드를 변환해 보겠습니다(또한 처음 두 줄을 배열을 올바르게 지우는 코드로 바꿉니다).
set -A F_ARR
find "$CDIR" ! -type d -mtime +7 -print0 |&
while IFS= read -d '' -pr pathname; do
F_ARR+=("$pathname")
done
echo ${#F_ARR[@]}
이를 위해서는찾기(1)이 옵션은 지원되며 구현은 -print0
NUL 종료 회선을 지원할 만큼 충분히 새롭습니다. Korn Shell이 오래된 경우에는 사용하지 마십시오(그러나 둘 중 하나도 지원하지 않으므로 충분히 새로운 것일 가능성이 높습니다).mksh
-d ''
+=(…)
전체 공개: 나는므케시개발자.
답변3
잠시 고민하다가 선생님의 코딩 방식을 대부분 유지하기로 결정했습니다.
저는 ksh에 익숙하지 않아서 bash로 코딩해야 합니다.
번역이 필요하시면 죄송합니다.
배열 값을 전달할 수 없도록 파이프라인에 서브셸을 생성하므로 임시
파일 이 필요합니다.for
while
mktemp
임시 파일이 처리할 필요가 없는 디렉토리에 배치 되도록 파일 모드를 변경할 수 있습니다 .
while 루프의 에코 부분을 코드로 바꾸십시오.
#!/bin/bash
i=0
tmp=`mktemp /tmp/findingXXXXXX`
find "$CDIR" ! -type d -mtime +7 |awk '{print "F_ARR["(NR-1)"]="$0}' >$tmp
. $tmp
rm -f $tmp
while [ "${F_ARR[$i]}" != "" ];
do
echo i=$i ${F_ARR[$i]}
((i++))
done