Eu quero atuar em uma lista de subdiretórios em um diretório. Considerar:
for x in x86-headers/*/C/populate.sh; do echo $x; done
Isto dá
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
Mas eu quero valores que corresponde à segunda parte do caminho,
elf
, gl
, etc. Eu sei como retirar o líder x86-headers
.
for x in x86-headers/*/C/populate.sh; do i=${x##x86-headers/}; echo $i; done
que dá
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
Eu também sei como retirar termos posteriores no caminho. Ou seja, descendo um nível:
cd x86-headers
for x in */C/populate.sh; do i=${x%%/*}; echo $i; done
dá
elf
gl
gmp
gnome2
gtk2
jni
libc
Mas, tentar combinar isso não funciona. Ou seja,
for x in x86-headers/*/C/populate.sh; do i=${${x##x86-headers}%%/*}; echo $i; done
dá
bash: ${${x##x86-headers}%%/*}: bad substitution
Sem dúvida, esta é uma sintaxe incorreta, mas não conheço a sintaxe correta. Claro que pode haver melhores maneiras de fazer isso. Se eu estivesse usando Python, usaria split on /
para dividir cada caminho em uma lista e depois escolher o segundo elemento, mas não sei como fazer isso no bash.
EDIT: Obrigado pelas respostas. Eu também deveria ter perguntado, é possível fazer isso de forma portável? Se sim, como?
i=${x#*/}; i=${i%%/*}
é opcional, certo?ash
/dash
, executavam as atribuições da direita para a esquerda (como era o comportamento do shell Bourne) e causavam problemas nesse caso.A expansão de parâmetros não permite aninhar expressões; portanto, você é forçado a fazê-lo em duas etapas, com uma atribuição:
Você tem a opção de usar matrizes aqui, mas acho que seria mais complicado do que o PE acima:
Depois, há a terceira opção de usar comandos externos. Com uma pequena lista de arquivos, essa geralmente é a opção menos eficiente, mas será dimensionada da melhor maneira que o número de arquivos aumentar:
fonte
zsh
permite o aninhamento.bash
.fonte
Tenha muito cuidado usando uma construção como abaixo:
Como você pode acabar fazendo um
echo *
. Nesse caso, é apenas engraçado, mas pode ser muito pior se você é root,CWD
is is/
e você deseja excluir alguns subdiretórios em/tmp
vez de repeti-los!Para corrigir isso no bash, você pode fazer:
Observe o
shopt -u nullglob
no final para restaurar o comportamento padrão do bash após o loop.Uma solução mais portátil pode ser:
(As substituições
##
e de%%
parâmetros são válidas em ksh88 ).Siga este link para uma discussão mais completa sobre o nullglob .
Observe que as 3 soluções acima falham se você tiver um diretório intermediário com um espaço em seu nome. Para resolvê-lo, use aspas duplas na substituição da variável:
fonte
Para fazer a correspondência de padrões nos nomes dos caminhos de maneira portável, você pode definir a
IFS
variável do shell como/
e, em seguida, usar a expansão dos parâmetros do shell.Fazer tudo isso de forma resumida ajuda a manter o ambiente do shell pai inalterado!
fonte