Como escapar padrões de expansão de nome prolongadas em expressões citadas?
-
22-08-2019 - |
Pergunta
Além dos padrões básicos *
, ?
e [...]
, o shell Bash fornece operadores padrão correspondentes estendidas como !(pattern-list)
( "corresponder a todos, exceto um dos padrões dados"). A opção shell extglob
precisa ser configurado para usá-los. Um exemplo:
~$ mkdir test ; cd test ; touch file1 file2 file3
~/test$ echo *
file1 file2 file3
~/test$ shopt -s extglob # make sure extglob is set
~/test$ echo !(file2)
file1 file3
Se eu passar uma expressão de shell para um programa que executa-lo em um sub-shell, o operador provoca um erro. Aqui está um teste que dirige uma sub-shell diretamente (aqui eu estou executando a partir de outro diretório para se certificar de expansão não acontece prematuramente):
~/test$ cd ..
~$ bash -c "cd test ; echo *"
file1 file2 file3
~$ bash -c "cd test ; echo !(file2)" # expected output: file1 file3
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `cd test ; echo !(file2)'
Eu tentei todos os tipos de escapar, mas nada que eu vim acima com funcionou corretamente. Eu também suspeito extglob
não está definido em uma sub-shell, mas isso não é o caso:
~$ bash -c "shopt -s extglob ; cd test ; echo !(file2)"
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `cd test ; echo !(file2)'
Qualquer solução apreciada!
Solução
$ bash -O extglob -c 'echo !(file2)' file1 file3
Outras dicas
festa analisa cada linha antes de executá-lo, por isso "extglob shopt -s" não ter tido efeito quando o bash é validar a sintaxe padrão de englobamento. A opção não pode ser ativado na mesma linha. É por isso que a solução "bash -O extglob -c 'xyz'" (do Randy Proctor) funciona e é necessário.
Aqui está outra maneira, se você quiser evitar eval
e você precisa ser capaz de transformar extglob e desligar dentro do subnível. Basta colocar o seu padrão em uma variável:
bash -c 'shopt -s extglob; cd test; patt="!(file2)"; echo $patt; shopt -u extglob; echo $patt'
dá essa saída:
file1 file3
!(file2)
demonstrando que extglob foi activar e desactivar. Se o primeiro echo
tinha aspas em torno do $patt
, seria apenas cuspir o padrão como o segundo echo
(que provavelmente deve ter aspas).
Bem, eu não tenho nenhuma experimentar real com extglob , mas eu posso obtê-lo para o trabalho envolvendo a echo
em uma eval
:
$ bash -c 'shopt -s extglob ; cd test ; eval "echo !(file2)"'
file1 file3