Posso usar o comando find para passar argumentos para o perl?

2

Eu tenho um script perl

$ cat ~/script.pl
sub main {

    my ($file) = @_;

    <STUFF>

    }

}

foreach (@ARGV) {

    main($_);

}

Eu quero executar ~/script.pl em cada arquivo .txt sob o diretório ~/foo . Eu posso obter a lista de .txt arquivos em ~/foo com o comando

$ find ~/foo -type f -name \*.txt

Posso de alguma forma usar este comando para passar esses arquivos para o meu script?

    
por Brian Fitzpatrick 03.12.2015 / 07:16

3 respostas

11

Sim, existem várias maneiras de fazer isso com o comando find . Vou listar alguns na ordem que acho importante para entender sua situação.

  1. Seu script parece aceitar vários argumentos de nome de arquivo, portanto, a maneira mais eficiente e quase universal de realizar isso usando o comando find é:

    find ~/foo -type f -name \*.txt -exec perl ~/script.pl {} +
    

    Isso executa o seu script com tantos argumentos de nome de arquivo encontrados quanto possível. Seu script será chamado várias vezes, se necessário, para processar todos os nomes de arquivos. Observe o + no final da linha.

  2. Este é o método original e mais universal. Isso é menos eficiente para sua situação porque invoca perl uma vez para cada arquivo encontrado. Esse uso está disponível desde os primeiros dias do Unix . Observe o ponto e vírgula escapado ( \; ) no final da linha (em oposição ao + acima).

    find ~/foo -type f -name \*.txt -exec perl ~/script.pl {} \;
    
  3. Antes de a sintaxe -exec ... + ser adicionada a find , o comando xargs foi inventado para ajudar a aumentar a eficiência ao processar listas de nomes de arquivos ou outros argumentos. Isso funciona quase de forma idêntica ao exemplo -exec ... + acima:

    find ~/foo -type f -name \*.txt -print | xargs perl ~/script.pl
    

    Se sua implementação for compatível, você deve usar a opção -print0 de find , junto com o argumento -0 para xargs . Isso faz com que find imprima caracteres nulos entre as sequências de argumentos e impede que xargs divida os argumentos em nada, exceto no caractere nulo. Isso ajuda a impedir que xargs divida os argumentos incorretamente, caso seus nomes de arquivos contenham espaços em branco ou outros caracteres especiais.

    Usar a sintaxe -exec ... + geralmente é uma ideia melhor porque find coloca os nomes de arquivos diretamente na lista de argumentos do seu script, eliminando um processo e evitando qualquer interpretação que possa ocorrer ao canalizar para xargs . No entanto, xargs pode ter vantagens se você precisar de mais controle sobre o processo. Veja a página xargs man.

  4. Você também pode verificar o comando find2perl , que recebe os mesmos argumentos de find e imprime um programa perl para fazer a mesma coisa. Você poderia então incorporar o código perl gerado em seu script. No script gerado abaixo, você modificaria o próximo da última linha para chamar sua função em vez de print .

    $ find2perl foo -type f -name \*.txt    # /*
    
    #[some preamble code removed for brevity]
    
    # Traverse desired filesystems
    File::Find::find({wanted => \&wanted}, 'foo');
    exit;
    
    sub wanted {
        my ($dev,$ino,$mode,$nlink,$uid,$gid);
    
        (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
        -f _ &&
        /^.*\.txt\z/s
        && print("$name\n");
    }   
    
por 03.12.2015 / 07:42
3

Como as outras respostas indicam - sim, você pode.

Vou sugerir uma alternativa - não, e use o perl embutido em File::Find - que permite fazer basicamente a mesma coisa, mas autônomo.

Por exemplo:

#!/usr/bin/env perl
use strict;
use warnings;

use File::Find;

sub process {
    return unless -f;
    return unless m/\.txt$/; #regex style, not shell glob. 
    print "Found: Name of $_ as path $File::Find::name in $File::Find::dir\n"; 
}

find ( \&process, '~/foo' ); 

Você pode codificar o caminho ( ~/foo ) ou lê-lo em @ARGV .

 find ( \&process, @ARGV ); #takes as many paths as you specify as args. 
    
por 03.12.2015 / 10:41
1

Sim, com -exec scriptName.sh {} \; structure

No seu caso particular, isso seria

find ~/foo -type f -name \*.txt -exec scriptName.sh {} \;

Alternativa para isso seria passar os arquivos para xargs , usando o separador nulo.

Obtido diretamente do manual xargs é este exemplo

 find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f
    
por 03.12.2015 / 07:46

Tags