Faça 'find -regextype egrep' como alias

4

Estou apenas começando a aprender regex e quero usá-lo em vez de outros em qualquer lugar para praticar.

Encontrei essa situação quando tentei encontrar arquivos com extensões sh or md

$ find . regex ".*\.(sh|md)$"
.
./bogus.py
./cofollow.py
./data8.txt
./example.sh
./longest_word_2.sh
./posit_param.sh
./cobroadcast2.py

Infelizmente, ele gera /bogus.py ,

Eu observo as regras do BRE e tentei escapar ()

$ find . -regex ".*\.\(sh|md\)$"
#get nothing return

Após uma série de pesquisas, obtive a solução -regextype Regular Expressões - Localizando arquivos

$ find . -regextype posix-extended -iregex ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh

$ find . -regextype egrep -iregex ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh
./table_regex_bat.md

Além disso, uma ótima solução modular

$ find -type f | egrep ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh
./table_regex_bat.md

No entanto, existe um atalho no BSD para realizar essa tarefa com um predicado -E .

$ /usr/bin/find -E . -regex ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh

Estou determinado a usar exclusivamente a ferramenta GNU para tornar meus códigos e habilidades portáveis.

Portanto, estou começando a encontrar alias -regextype egrep ',
Infelizmente, encontre o $ 1 como caminho.

Como eu poderia resolver o problema de uma maneira útil?

    
por JawSaw 02.11.2018 / 05:18

3 respostas

7

Não use um alias para passar argumentos. Eles não são portáteis e úteis apenas em shells interativos. Use uma função e passe os argumentos como caminhos necessários

regexFind() {
    (( "$#" )) || { printf 'Insufficient arguments provided \n' >&2; return 1; }
     find "$1" -regextype egrep -iregex ".*\.(sh|md)$"
}

e chame a função como

regexFind "/home/foo/bar"

Além disso, para adicionar às suas descobertas, observe que bash também possui uma maneira intrínseca de globar arquivos. Você só precisa ativar algumas opções de shell estendidas para fazê-lo funcionar. O -s ativa a opção e -u a desativa.

O nullglob permite ignorar os resultados do glob não-expandidos como correspondências válidas. Portanto, supondo que você queira corresponder arquivos que terminam com *.sh e *.md , você só precisa navegar para esse diretório específico e fazer

shopt -s nullglob
fileList=(*.sh)
fileList+=(*.md)
shopt -u nullglob

e imprima os resultados para ver abaixo. Lembre-se de citar a expansão para evitar que os nomes dos arquivos passem por divisão de palavras.

printf '%s\n' "${fileList[@]}"
    
por 02.11.2018 / 05:23
4

Observe que os regexps padrão do GNU find não são BRE, mas os REs do emacs (algum tipo de híbrido entre BRE e ERE, por exemplo, + é suportado, mas você precisa de \(...\) e | suportado, mas como \| ).

Com BSD find , o padrão é BRE, e você pode usar a opção -E para habilitar os EREs, então, é só uma questão de:

alias efind='find -E'

ou:

efind() { find -E "$@"; }

No GNU find , a ativação de EREs é com um predicado -regextype posix-extended , não uma opção. Esse predicado deve aparecer após os nomes dos arquivos que, se presentes, devem aparecer após as opções e antes do -regex ou -iregex que faz uso deles.

A sintaxe find do GNU é:

find [options] [files] [predicates]
                      ^

Então você precisa inseri-lo lá (na posição marcada com ^ ).

Portanto, ao definir uma função ou script de wrapper, você precisa levar isso em conta: ignore todas as opções e nomes de arquivos e insira o -regextype posix-extended logo após eles.

efind() (
  found_predicate=false
  for arg do
    "$found_predicate" || case $arg in
      (-[LPDd]|-[OD]*) ;;  # skip options
      (-*|['()!'])
        set -- "$@" -regextype posix-extended
        found_predicate=true;;
    esac
    set -- "$@" "$arg"
    shift
  done

  exec find "$@"
)

Algumas outras notas:

  • seu primeiro impresso bogus.py não porque o BRE foi usado, mas porque você usou regex em vez de -regex . regex foi considerado um nome de arquivo, não um predicado.
  • find . | egrep ... não é válido porque os caminhos de arquivo podem ser feitos de mais de uma linha. Com ferramentas GNU ou compatível, você pode fazer find . -print0 | grep -zE ... para trabalhar com registros delimitados por NUL (e canalizar para tr '%code%' '\n' se for para exibição.
por 02.11.2018 / 11:05
3
find . -type f \( -name '*.sh' -o -name '*.md' \)

Isso funcionaria com todas as implementações de find , já que não requer suporte para correspondência de expressões regulares.

Para tornar isso mais flexível:

suffixfind () (
    dir=$1
    shift

    for suf do
        set -- "$@" -o -name "*.$suf"
        shift
    done
    shift

    find "$dir" -type f \( "$@" \)
)

Esta função de shell auxiliar (que funcionaria em qualquer shell sh -like) selecionaria o primeiro argumento de linha de comando e o colocaria na variável dir . Em seguida, ele criaria uma lista de -name "*.<suf1>" -o -name "*.<suf2>" (etc.) com todos os sufixos de nome de arquivo na linha de comando da função antes de chamar find com essa lista para localizar arquivos em ou abaixo de $dir .

Você usaria como

suffixfind /usr sh md txt

para localizar todos os arquivos regulares com nomes que terminem em .sh , .md ou .txt no caminho /usr .

Uma variação um pouco mais detalhada das variáveis acima usando bash arrays e bash local:

suffixfind () {
    local dir=$1
    shift

    local names

    names=( -name "*.$1" )
    shift
    for suf do
        names+=( -o -name "*.$suf" )
    done

    find "$dir" -type f \( "${names[@]}" \)
}

Sobre sua menção de ferramentas GNU e portabilidade: Observe que as ferramentas GNU em sistemas não Linux às vezes estão disponíveis, mas com um prefixo g para os nomes das ferramentas. Portanto, o% GNUfind estaria disponível como gfind para diferenciá-lo da implementação find nativa no sistema.

Sua abordagem "GNU portável" teria, portanto, que testar se gfind estava disponível antes de testar se find é de fato GNU find . Não até que você tenha feito isso (possivelmente testando o status de retorno e a saída de find --version ) você se sentirá confortável em saber que está lidando com o GNU find .

    
por 02.11.2018 / 08:42

Tags