이름만을 기준으로 for 루프에서 하위 디렉터리를 건너뛰는 방법은 무엇입니까?

이름만을 기준으로 for 루프에서 하위 디렉터리를 건너뛰는 방법은 무엇입니까?

다음과 같은 방식으로 하위 디렉터리로 구성된 디렉터리가 있습니다.

a1
b1
c1
c2
c3
d1

주어진 문자의 최신 하위 디렉터리에서만 수행되는 루프를 수행하려고 합니다. 즉 a1, b1, c3, 및 을 반복하지만 합계는 d1무시합니다 . 지금까지의 노력은 하위 디렉터리 이름의 수치를 직접 비교하는 것에만 집중했는데, 잘 되지 않았습니다. 나는 bash를 처음 접했기 때문에 이것이 내가 놓친 간단한 수정 사항이라면 사과드립니다.c1c2

답변1

이것은 당신의 목표를 달성한 것 같습니다

#!/bin/bash
for DIR in {a..z}
do
 GOOD=$(find ${DIR}[0-9] -type d -print -prune 2>/dev/null | tail -1)
 if [[ "$GOOD" ]]; then
  echo $GOOD
 fi
done

사용 예:

$ mkdir a1 b1 c1 c2 c3 d1
$ ./a.sh
a1
b1
c3
d1
$

답변2

귀하의 작업을 수행하는 약간 복잡한 파이프라인이 있습니다.

#!/bin/bash
find . -maxdepth 1 -type d |
sed -e '/\.$/d' -e '/\.\.$/d' -e 's/\.\/\(.\)\(.\)/\1   \2/' |
sort -k1.1 -k2.1n |
awk 'BEGIN {last=""}
        {
                if (last == "") {
                        last = $1; number = $2
                } else if ($1 != last) {
                        printf "%s%s\n", last, number;
                        last = $1; number = $2
                } else {
                        number = $2
                }
        }
        END { printf "%s%s\n", last, number }
'

find원하는 결과를 얻으 려면 매개변수를 변경해야 할 수도 있습니다 .

답변3

시리즈의 마지막 요소에 대해 작업하는 한 가지 방법은 이전 항목을 기억하면서 모든 요소를 ​​반복하는 것입니다. 새로운 시리즈가 곧 시작될 것임을 감지하면 기억된 이전 항목에 대해 조치를 취하세요. 테스트되지 않은 코드. 나는 당신이 첫 번째 문자가 점이 아니고 마지막 문자가 숫자인 디렉토리에만 관심이 있다고 가정합니다.

act_on () {
}
previous_prefix=0
previous_name=
for x in *[0-9]/; do
  x=${x%/}
  digits=${x##*[!0-9]}
  prefix=${x%"$digits"}
  if [ "$prefix" != "$previous_prefix" ] && [ "$previous_prefix" != "0" ]; then
    # New prefix, so act on the previous element
    act_on "$previous_name"
  fi
  previous_prefix=$prefix
  previous_name=$x
done
act_on "$previous_name"

foo9이후에 정렬된다는 점에 유의하세요 foo10. zsh에서 use는 이전에 정렬된 *[0-9](/on)숫자 정렬을 사용합니다 . zsh를 사용하지 않는 경우 다른 접근 방식을 취해야 합니다. 한 가지 접근 방식은 계열의 첫 번째 항목에 대해서만 연산을 수행하고, 찾은 항목에 대해 연산을 수행하는 대신 접두사를 사용하여 숫자 계열의 마지막 요소를 결정하는 것입니다.910

act_on () {
}
previous_prefix=0
previous_name=
for x in *[0-9]/; do
  x=${x%/}
  digits=${x##*[!0-9]}
  prefix=${x%"$digits"}
  if [ "$prefix" != "$previous_prefix" ]; then
    suffixes=
    for y in "$prefix"*; do
      suffixes="$suffixes
${y#"$prefix"}"
    done
    last_suffix=$(echo "$suffixes" | sort -n | tail -n 1)
    act_on "$prefix$last_suffix"
  fi
  previous_prefix=$prefix
  previous_name=$x
done

답변4

디렉토리 이름이 표시한 것처럼 간단하다면(적어도 공백이나 기타 이상한 내용이 포함되지 않은 경우) 다음을 수행할 수 있습니다.

for d in $(ls | sort -r | rev | uniq -s1 | rev); do echo "$d"; done

이것을 루프가 수행해야 하는 작업으로 echo "$4d"변경합니다 . 그러나 디렉터리 이름이 표시된 이름과 정확히 일치하지 않으면 모든 오류에 취약하므로 이 작업은 실패합니다.ls 구문 분석은 먼저 디렉터리를 나열하고 역순으로 정렬한 다음 역순으로( 가 됨 a1) 1a고유한 줄만 유지하고 첫 번째 문자( uniq -s1)를 무시한 다음 다시 역순으로 복원하여 원래 이름을 복원하는 방식으로 작동합니다.

관련 정보