我想对目录中的子目录列表进行操作。考虑:
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
但是,尝试将这些结合起来是行不通的。 IE
for x in x86-headers/*/C/populate.sh; do i=${${x##x86-headers}%%/*}; echo $i; done
给出
bash: ${${x##x86-headers}%%/*}: bad substitution
毫无疑问这是不正确的语法,但我不知道正确的语法。当然可能有更好的方法来做到这一点。如果我使用 Python,我会使用 split on/
将每个路径分解为一个列表,然后选择第二个元素,但我不知道如何在 bash 中执行此操作。
编辑:感谢您的回答。我还应该问,是否可以便携地做到这一点,如果可以,如何实现?
答案1
你不能将它们与bash
(或 POSIXly)结合起来,你必须分两步完成。
i=${x#*/}; i=${i%%/*}
它可以移植到任何 POSIX shell。如果您需要 Bourne shell 的可移植性(但为什么要标记您的问题/bash那么?)如果您要移植到 Solaris 并被迫使用那里的/bin/sh
标准sh
,或者移植到 20 年前的系统),您可以使用此方法(该方法也适用于 POSIX shell):
IFS=/; set -f
set x $x
i=$3
(上面是极少数情况之一,将变量不加引号是有意义的)。
仅供记录,使用 zsh:
print -rl -- x86-headers/*/C/populate.sh(:h:h:t)
(这t所有的H的头H文件的开头)。
或者对于你的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
shell 变量设置为/
,然后使用 shell 参数扩展。
在子 shell 中执行所有这些操作有助于保持父 shell 的环境不变!
# 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