find: tratar barra especialmente

1

Gostaria de usar find para corresponder a um caminho, mas achei isto:

-path pattern

File name matches shell pattern pattern. The metacharacters do not treat /' or.' specially; so, for example,

  find . -path "./sr*sc"

will print an entry for a directory called ./src/misc (if one exists).

Como posso fazer com que ele corresponda apenas aos arquivos no diretório atual? Preciso de outra ferramenta para este trabalho?

Editar. Como sugerido, aqui estão alguns detalhes. Para fazer este trabalho, existem -maxdepth e -regex para uso. No entanto, em aplicações reais, o caminho pode ser uma variável em vez de uma constante simples aqui, em que -maxdepth não funciona bem e -regex pode parecer um exagero. Então, eu gostaria de saber se há uma solução simples com find para fazer a barra de respeito. Abaixo está o doc do rsync descrevendo seu comportamento, que é muito próximo do que eu quero.

Atualmente, a melhor solução é usar o regex, mas, se você souber de alguma coisa que possa tornar mais simples, será bem-vindo.

Como exemplo do que eu quero, aqui está a regra do padrão rsync:

  • a '*' corresponde a qualquer componente do caminho, mas para nas barras.

  • use '**' para corresponder a qualquer coisa, incluindo barras.

por Cyker 31.07.2018 / 18:30

3 respostas

2

Use -regex . O padrão é ancorado no início e no final, portanto, você precisará usar .* no início e no final, provavelmente. Use [^/]*/ para substituir um glob * que não corresponde a / . Por exemplo:

-regex '.*/sr[^/]*sc.*'

Existe um pequeno script Perl find2perl que pretende converter os argumentos para um comando find em um script Perl equivalente. Obviamente, ele terá o mesmo padrão de correspondência para -path como find , mas você pode editá-lo para aceitar outro argumento, digamos -glob , que usaria a chamada de sistema fnmatch() para fazer o tipo de globbing quer. Fiz uma modificação rápida na minha versão de find2perl , conforme mostrado neste patch:

--- /usr/bin/find2perl  2016-02-04 19:28:48.000000000 +0100
+++ /tmp/find2perl      2018-07-31 20:38:10.034175198 +0200
@@ -58,2 +58,4 @@
     $out .= tab . '$File::Find::name =~ /' . fileglob_to_re(shift) . "/s$1";
+    } elsif (/^glob$/) {
+        $out .= tab . 'fnmatch("'.(shift).'", $name, FNM_PATHNAME|FNM_PERIOD)';
 } elsif ($_ eq 'perm') {
@@ -236,2 +238,3 @@
 use File::Find ();
+use File::FnMatch qw(:fnmatch);    # import everything

(As linhas que começam com + mostram as 3 linhas que adicionei). Eu precisava adicionar pacotes perl-App-find2perl e perl-File-FnMatch para o Fedora. Você precisaria encontrar o equivalente em seu sistema.

Você pode então executar comandos como

/tmp/find2perl . -glob './sr*sc' | perl
    
por 31.07.2018 / 18:39
1

Para evitar que find recorra a subdiretórios, use -maxdepth flag

find -maxdepth 1 -name "sr*sc"
    
por 31.07.2018 / 18:36
1

Alguns shells, como zsh , bash e ksh93 , suportam o padrão de globbing de nomes de arquivo ** . Em zsh , ele é ativado por padrão, enquanto bash precisa ativá-lo com shopt -s globstar e ksh93 com set -o globstar .

Isso significa que você deve ser capaz de fazer, por exemplo,

for pathname in ./src/**/misc/*.c
    # process "$pathname" here
done

Alguns testes find , como -type f , poderiam ser facilmente incorporados a isso:

for pathname in ./src/**/misc/*.c
    [ -f "$pathname" ] || continue  # will not skip symbolic links to regular files though
    # process "$pathname" here
done
    
por 31.07.2018 / 19:23

Tags