디렉토리 내의 하위 디렉토리 목록을 작업하고 싶습니다. 고려하다:
for x in x86-headers/*/C/populate.sh; do echo $x; done
이것은
x86-headers/elf/C/populate.sh
x86-headers/gl/C/populate.sh
x86-headers/gmp/C/populate.sh
x86-headers/gnome2/C/populate.sh
x86-headers/gtk2/C/populate.sh
x86-headers/jni/C/populate.sh
x86-headers/libc/C/populate.sh
하지만 경로의 두 번째 부분 등에 해당하는 값을 원합니다 elf
. gl
나는 선행을 제거하는 방법을 알고 있습니다 x86-headers
.
for x in x86-headers/*/C/populate.sh; do i=${x##x86-headers/}; echo $i; done
이것은 만든다
elf/C/populate.sh
gl/C/populate.sh
gmp/C/populate.sh
gnome2/C/populate.sh
gtk2/C/populate.sh
jni/C/populate.sh
libc/C/populate.sh
또한 경로에서 후속 용어를 제거하는 방법도 알고 있습니다. 즉, 한 수준을 낮춥니다.
cd x86-headers
for x in */C/populate.sh; do i=${x%%/*}; echo $i; done
주어진
elf
gl
gmp
gnome2
gtk2
jni
libc
그러나 이들을 결합하려고 하면 작동하지 않습니다. 즉
for x in x86-headers/*/C/populate.sh; do i=${${x##x86-headers}%%/*}; echo $i; done
주어진
bash: ${${x##x86-headers}%%/*}: bad substitution
의심할 바 없이 이것은 잘못된 구문이지만 올바른 구문을 모르겠습니다. 물론 이보다 더 좋은 방법이 있을 수도 있습니다. Python을 사용하는 경우 분할을 사용하여 /
각 경로를 목록으로 나눈 다음 두 번째 요소를 선택하지만 bash에서 이 작업을 수행하는 방법을 모르겠습니다.
편집: 답변해 주셔서 감사합니다. 또한 이 이식성이 가능한지, 그렇다면 어떻게 할 수 있는지도 물어봐야 합니다.
답변1
(또는 POSIXly) 와 결합할 수 없으며 bash
두 단계로 수행해야 합니다.
i=${x#*/}; i=${i%%/*}
모든 POSIX 쉘로 이식 가능합니다. Bourne Shell의 이식성이 필요한 경우(그러나 질문에 태그를 지정하는 이유는 무엇입니까?)/세게 때리다그래서? ) Solaris로 포팅하고 그곳의 /bin/sh
표준을 강제로 사용 sh
하거나 20년 된 시스템으로 포팅하는 경우) 이 방법을 사용할 수 있습니다(이 방법은 POSIX 셸에서도 작동합니다):
IFS=/; set -f
set x $x
i=$3
(위의 경우는 변수를 따옴표로 묶지 않은 상태로 두는 것이 의미가 있는 드문 경우 중 하나입니다.)
기록을 위해 zsh를 사용합니다.
print -rl -- x86-headers/*/C/populate.sh(:h:h:t)
(이것티모두시간머리시간파일의 시작 부분).
또는 귀하의 python
방법에 따라:
x=elf/C/populate.sh
i=${${(s:/:)x}[2]}
답변2
매개변수 확장에서는 표현식 중첩이 허용되지 않으므로 두 단계로 수행하고 할당을 수행해야 합니다.
i=${x##x86-headers/}
i=${i%%/*}
여기서 배열을 사용할 수 있는 옵션이 있지만 위의 PE보다 더 번거롭다고 생각합니다.
IFS=/
set -f # Disable globbing in case unquoted $x has globs in it
i=( $x )
set +f
echo "${i[1]}"
그런 다음 외부 명령을 사용하는 세 번째 옵션이 있습니다. 이는 일반적으로 짧은 파일 목록의 경우 효율성이 가장 낮은 옵션이지만 파일 수가 증가함에 따라 가장 잘 확장됩니다.
# For clarity, assume no names have linebreaks in them
find . -name populate.sh | cut -d / -f 3
답변3
regex="x86-headers/([^/]*)/.*"
for f in x86-headers/*/C/populate.sh; do [[ $f =~ $regex ]] && echo "${BASH_REMATCH[1]}"; done
elf
gl
gmp
gnome2
gtk2
jni
libc
답변4
이식 가능한 패턴 일치 경로 이름을 위해 IFS
쉘 변수를 로 설정한 /
다음 쉘 매개변수 확장을 사용할 수 있습니다.
하위 쉘에서 이 모든 작업을 수행하면 상위 쉘의 환경을 그대로 유지하는 데 도움이 됩니다!
# cf. "The real Bourne shell problem",
# http://utcc.utoronto.ca/~cks/space/blog/programming/BourneShellLists
paths='
x86-headers/elf/C/populate.sh
x86-headers/gl/C/populate.sh
x86-headers/gmp/C/populate.sh
x86-headers/gnome2/C/populate.sh
x86-headers/gtk2/C/populate.sh
x86-headers/jni/C/populate.sh
x86-headers/libc/C/populate.sh
'
IFS='
'
# version 1
for x in $paths; do
( IFS='/'; set -- ${x}; echo "$2" );
done
# version 2
set -- ${paths}
for x in $@; do
( IFS='/'; set -- ${x}; echo "$2" );
done