encontrar dentro da função shell

1

Eu tento colocar find dentro da função e pegar um argumento passado para esta função com o seguinte exemplo de trabalho mínimo:

function DO
{
    ls $(find . -type f -name "$@" -exec grep -IHl "TODO" {} \;)
}

Mas, quando executo DO *.tex , recebo “find: os caminhos devem preceder a expressão:”. Mas quando faço diretamente:

ls $(find . -type f -name "*.tex" -exec grep -IHl "TODO" {} \;)

então eu recebo todos os arquivos TeX que contêm "TODO".

Eu tento muitas coisas na função DO , como \"$@\" , '$@' , altero as marcas de aspas, mas o comportamento continua o mesmo.

Então, o que fazer para forçar a encontrar trabalho dentro da função?

    
por fauve 20.06.2018 / 09:18

2 respostas

5

Existem alguns problemas no seu código:

  1. O padrão *.tex será expandido ao chamar a função DO , se corresponder a qualquer nome de arquivo no diretório atual. Você terá que citar o padrão como '*.tex' , "*.tex" ou \*.tex ao chamar a função.

  2. O ls não é necessário. Você já tem os dois find e grep que podem relatar os nomes de caminho dos arquivos encontrados.

  3. -name "$@" só funciona corretamente se "$@" contiver um único item. Seria melhor usar -name "$1" . Para uma solução que permite vários padrões, veja abaixo.

A função pode ser escrita

DO () {
   # Allow for multiple patterns to be passed,
   # construct the appropriate find expression from all passed patterns

   for pattern do
       set -- "$@" '-o' '-name' "$pattern"
       shift
   done

   # There's now a -o too many at the start of "$@", remove it
   shift

   find . -type f '(' "$@" ')' -exec grep -qF 'TODO' {} ';' -print
}

Chamando essa função como

DO '*.tex' '*.txt' '*.c'

fará com que seja executado

find . -type f '(' -name '*.tex' -o -name '*.txt' -o -name '*.c' ')' -exec grep -qF TODO {} ';' -print

Isso geraria uma lista de nomes de caminho de arquivos com esses sufixos de nome de arquivo, se os arquivos contivessem a string TODO .

Para usar grep em vez de find para imprimir os nomes de caminho encontrados, altere o -exec ... -print bit para -exec grep -lF 'TODO' {} + . Isso será mais eficiente, especialmente se você tiver um grande número de nomes de arquivos correspondentes à (s) expressão (ns) dada (s). Em ambos os casos, você definitivamente não precisa usar ls .

Para permitir que o usuário use

DO tex txt c

sua função pode ser alterada para

DO () {
   # Allow for multiple patterns to be passed,
   # construct the appropriate find expression from all passed patterns

   for suffix do
       set -- "$@" '-o' '-name' "*.$suffix"   # only this line (and the previous) changed
       shift
   done

   # There's now a -o too many at the start of "$@", remove it
   shift

   find . -type f '(' "$@" ')' -exec grep -qF 'TODO' {} ';' -print
}
    
por 20.06.2018 / 09:42
0

Você precisa citar o parâmetro para a função, caso contrário, o shell a expandirá e a função obterá uma lista de arquivos, não uma máscara curinga:

DO "*.tex"

Você pode usar apenas "$1" em vez de "$@" , pois haverá apenas um parâmetro.

    
por 20.06.2018 / 09:20