디렉토리의 하위 디렉토리 목록에서 작업하고 싶습니다. 치다:
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
의심 할 여지없이 이것이 잘못된 구문이지만 올바른 구문을 모르겠습니다. 물론 더 좋은 방법이있을 수 있습니다. 파이썬을 사용하고 있다면 split on /
을 사용 하여 각 경로를 목록으로 나누고 두 번째 요소를 선택하지만 bash에서 어떻게 해야하는지 모르겠습니다.
편집 : 답변 주셔서 감사합니다. 나도 물었을 것입니다.이를 이식 가능하게 할 수 있습니까? 그렇다면 어떻게합니까?
답변
그것들을 bash
(또는 POSIXly) 와 결합 할 수 없으므로 두 단계로 수행해야합니다.
i=${x#*/}; i=${i%%/*}
POSIX 쉘에 이식 가능합니다. Bourne 쉘로 이식성이 필요한 경우 (그러나 왜 / bash에 태그를 추가해야 합니까?) 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)
합니다 ( t에서 의 AIL 시간 의 EAD 시간은 파일의 EAD).
또는 당신의 python
접근 방식 :
x=elf/C/populate.sh
i=${${(s:/:)x}[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
답변
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
답변
다음과 같이 구문을 사용하여 매우주의하십시오.
# What happen if no files match ?
for x in x86-headers/*/C/populate.sh; do
x=${x##x86-headers/}
x=${x%%/*}
echo $x
done
당신이 결국 할 수있는 것처럼 echo *
. 이 경우에, 그것은 재미 있지만, 당신이 루트라면, 당신 CWD
은입니다. /
그리고 당신은 /tmp
그것들을 에코하는 대신에 몇몇 서브 디렉토리를 삭제하고 싶을 때 훨씬 최악 일 수 있습니다!
bash에서 수정하려면 다음을 수행하십시오.
shopt -s nullglob
for x in x86-headers/*/C/populate.sh; do
x=${x##x86-headers/}
x=${x%%/*}
echo $x
done
shopt -u nullglob
주목 shopt -u nullglob
루프 후 기본 bash는 동작을 복원하는 말.
보다 휴대용 솔루션은 다음과 같습니다.
for x in x86-headers/*/C/populate.sh; do
[ -e $x ] || break
x=${x##x86-headers/}
x=${x%%/*}
echo $x
done
( ##
및 %%
매개 변수 대체는 ksh88 에서 유효합니다 ).
nullglob 에 대한 자세한 내용은 이 링크를 참조 하십시오 .
이름에 공백이있는 중간 디렉토리가 있으면 위의 3 가지 솔루션이 실패합니다. 이 문제를 해결하려면 변수 대체에 큰 따옴표를 사용하십시오.
for x in x86-headers/*/C/populate.sh; do
[ -e "$x" ] || break
x="${x##x86-headers/}"
x="${x%%/*}"
echo "$x"
done
답변
경로 이름에서 패턴 일치를 수행하기 위해 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