bash中路径名的模式匹配

Fah*_*tha 10 bash string wildcards patterns

我想对目录中的子目录列表进行操作。考虑:

for x in x86-headers/*/C/populate.sh; do echo $x; done
Run Code Online (Sandbox Code Playgroud)

这给

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
Run Code Online (Sandbox Code Playgroud)

但我想要对应于路径第二部分的值 elfgl, 等。我知道如何去除前导x86-headers.

for x in x86-headers/*/C/populate.sh; do i=${x##x86-headers/}; echo $i; done
Run Code Online (Sandbox Code Playgroud)

这使

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
Run Code Online (Sandbox Code Playgroud)

我也知道如何去除路径中的后期术语。即下降一级:

cd x86-headers
for x in */C/populate.sh; do i=${x%%/*}; echo $i; done
Run Code Online (Sandbox Code Playgroud)

elf
gl
gmp
gnome2
gtk2
jni
libc
Run Code Online (Sandbox Code Playgroud)

但是,试图将这些结合起来是行不通的。IE

for x in x86-headers/*/C/populate.sh; do i=${${x##x86-headers}%%/*}; echo $i; done
Run Code Online (Sandbox Code Playgroud)

bash: ${${x##x86-headers}%%/*}: bad substitution
Run Code Online (Sandbox Code Playgroud)

毫无疑问,这是不正确的语法,但我不知道正确的语法。当然,可能有更好的方法来做到这一点。如果我使用 Python,我会使用 split on/将每个路径分成一个列表,然后选择第二个元素,但我不知道如何在 bash 中执行此操作。

编辑:感谢您的回答。我还应该问,是否可以便携地做到这一点,如果可以,如何做到?

Sté*_*las 9

您不能将它们与bash(或 POSIXly)结合使用,您必须分两步完成。

i=${x#*/}; i=${i%%/*}
Run Code Online (Sandbox Code Playgroud)

这可以移植到任何 POSIX shell。如果您需要可移植到 Bourne shell(但是为什么要标记您的问题/bash呢?)以及以防您移植到 Solaris 并被迫使用那里/bin/sh的标准而不是sh那里的标准,或者移植到 20 年前的系统) ,您可以使用这种方法(它也适用于 POSIX shell):

IFS=/; set -f
set x $x
i=$3
Run Code Online (Sandbox Code Playgroud)

(以上是非常罕见的情况之一,其中不加引号的变量是有意义的)。

仅作记录,使用 zsh:

print -rl -- x86-headers/*/C/populate.sh(:h:h:t)
Run Code Online (Sandbox Code Playgroud)

(该的的AIL ħ所述的EAD ħ EAD的文件)。

或者对于您的python方法:

x=elf/C/populate.sh
i=${${(s:/:)x}[2]}
Run Code Online (Sandbox Code Playgroud)

  • @DimitreRadoulov 这是可选的,但一些 shell 像 [一些旧版本的`ash`/`dash`](http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=334182) 会从右边运行分配向左(这是 Bourne shell 的行为方式)并在这种情况下导致问题。 (3认同)

koj*_*iro 7

参数扩展不允许您嵌套表达式,因此您必须分两步完成,并进行赋值:

i=${x##x86-headers/}
i=${i%%/*}
Run Code Online (Sandbox Code Playgroud)

您可以选择在此处使用数组,但我认为它比上面的 PE 更麻烦:

IFS=/
set -f # Disable globbing in case unquoted $x has globs in it
i=( $x )
set +f
echo "${i[1]}"
Run Code Online (Sandbox Code Playgroud)

然后是使用外部命令的第三个选项。对于简短的文件列表,这通常是效率最低的选项,但随着文件数量的增加,它的扩展性最好:

# For clarity, assume no names have linebreaks in them
find . -name populate.sh | cut -d / -f 3
Run Code Online (Sandbox Code Playgroud)

  • @StephaneChazelas 很公平,但这个问题被标记为“bash”。 (3认同)