Como adicionar listas de argumentos agrupados opcionais para encontrar?
Por exemplo, usando uma matriz de argumentos base que definem arquivos que sempre serão encontrados, não importa quais outras condições de variáveis sejam especificadas.
# args to find any files ending _count or _scan
._. fargs=( -type f -name '*_count' -o -name '*_scan' )
._. cd /sys/fs/ext4/sda1
._. find . \( "${fargs[@]}" \) 2> /dev/null
./mb_min_to_scan
./errors_count
./mb_max_to_scan
./msg_count
./warning_count
Adicionar argumentos adicionais opcionais
._. fpterm=warning
._. fpterm2=max
._. fANDargs=( -ipath "*$fpterm*" -o -ipath "*$fpterm2*" )
Aplique os argumentos opcionais entre parênteses para executar find com o formulário: ( a ou b ou c ) e ( d ou e ou f )
._. find . \( "${fargs[@]}" \) \( "${fANDargs[@]}" \) 2> /dev/null
./dm-1/mb_max_to_scan
./dm-1/warning_count
./dm-0/mb_max_to_scan
./dm-0/warning_count
./sda1/mb_max_to_scan
./sda1/warning_count
Mas quando a matriz arg opcional está vazia, ela impede que outras condições sejam atendidas e nenhum arquivo é encontrado:
._. fANDargs=()
._. find . \( "${fargs[@]}" \) \( "${fANDargs[@]}" \) 2> /dev/null
._.
O parêntese vazio causa o problema:
._. find . \( "${fargs[@]}" \) \( \) 2> /dev/null
._.
Considerando que, normalmente, uma matriz arg vazia não impede que outras condições sejam atendidas:
._. fANDargs=()
._. echo "${fANDargs[@]}"
._. find . \( "${fargs[@]}" \) "${fANDargs[@]}" 2> /dev/null
...
./sda1/mb_min_to_scan
./sda1/errors_count
./sda1/mb_max_to_scan
./sda1/msg_count
./sda1/warning_count
Portanto, se os colchetes puderem ser adicionados somente quando a matriz opcional args não estiver vazia, o comando poderá funcionar.
Mas como os colchetes podem ser adicionados condicionalmente?
Parece não funcionar quando você adiciona o parêntese à matriz, por exemplo:
._. fpterm=warning
._. fANDargs=()
._. [ ! -z $fpterm ] && fANDargs+=( '\(' -ipath "*$fpterm*" '\)' )
._. echo "${fANDargs[@]}"
\( -ipath *warning* \)
._. find . \( "${fargs[@]}" \) "${fANDargs[@]}" 2> /dev/null
._.
Você está citando duas vezes aqui. Tente com apenas uma camada:
(Também você deve usar aspas em
[ ! -z "$fpterm" ]
)Em geral, você usaria as palavras na atribuição de matriz exatamente como as usaria diretamente em um comando. O uso
"${array[@]}"
com aspas (como você fez) expandiria para o conteúdo da matriz sem modificações adicionais .(Esta é a parte em que as pessoas geralmente parecem errar, elas parecem esperar que o shell processa citações sobre os resultados das expansões. Isso não acontece, é mais como uma linguagem de programação "normal" aqui. Desde que você use as aspas para obter livrar-se do incômodo split+glob.)
Claro, o pano de fundo aqui é que o que
find
ele quer ver são apenas os parênteses como estão (como argumentos distintos). Ele não precisa ver as aspas, mas o shell precisa delas, pois os parênteses são caracteres especiais que fazem parte da sintaxe do shell. Portanto, você pode usarsomecmd { foo bar }
sem aspas, mas precisa de algumas citações ou escape emsomecmd \( foo bar \)
.BTW, o GNU find avisa sobre um conjunto vazio de parênteses:
E, bem, logicamente parece estranho de qualquer maneira. Meu primeiro instinto seria dizer que os parênteses vazios devem ser avaliados como falsos, o que faria
find \( whatever \) \( \)
sempre corresponder a nada. Mas também pode ser interpretado como verdadeiro, e isso parece ser o que o Busybox faz,busybox find . \( \) -name '*.txt'
dá o mesmo quebusybox find . -name '*.txt'
.