GNU find: obter caminho absoluto e relativo em -exec

0

Eu tenho um comando (não echo !) que eu quero executar, que tem um caminho absoluto e um caminho relativo.

Como obtenho esses dois argumentos?

Tentativa:

d=/tmp/foo;
find "$d" -type f -exec bash -c 'echo d=${1:${#d}} 1="${1%/*}"' bash {} \;

(Eu gosto do GNU find porque é recursivo, pode restringir por arquivo, pode filtrar por nome de arquivo e não gera shells em excesso)

Expectativa:

mkdir -p /tmp/foo/bar/can/haz; touch /tmp/foo/bar/can/haz/bzr.txt
# cmd is run, output is:
d=bar/can/haz 1=/tmp/foo/bar/can/haz
    
por A T 23.11.2017 / 13:41

1 resposta

4

Exportar d , depois estará disponível no seu script bash inline. Você também não precisa de bash aqui. Seu (espero que mais magro / mais rápido) sh também funcionaria. Além disso, você não precisa executar um shell por arquivo. Você pode enviar mais arquivos para seu script in-line com a variante -exec cmd {} + :

d=/tmp/foo
export d
find "$d" -type f -exec sh -c '
  for file do
    relative=${file#"$d/"}
    dir=${file%/*}
    relative_dir=${relative%/*}
    relative_dir=${relative_dir:-.}
    printf "%10s: %s\n" full "$file" \
                        relative "$relative" \
                        dir "$dir" \
                        reldir "$relative_dir"
  done' sh {} +

O que dá:

      full: /tmp/foo/bar/can/haz/bzr.txt
  relative: bar/can/haz/bzr.txt
       dir: /tmp/foo/bar/can/haz
    reldir: bar/can/haz

Mas se você precisar apenas do caminho relativo, pode ser mais simples fazer isso:

(cd -P -- "$d" && find . -exec sh -c 'for file do...' sh {} +)

Isso também faria com que os argumentos de comando passassem para sh mais curto, então permitiria que find passasse mais argumentos para sh .

Note que não há nada específico para o GNU no seu comando find nem no meu. Isso deve funcionar em qualquer implementação find compatível com POSIX, não apenas na GNU. A única parte não POSIX em sua pergunta era obviamente bash e o operador ${1:offset} que é um operador de shell Korn, não em POSIX sh .

Para uma pesquisa de arquivos recursiva que permite especificar o tipo de arquivo, consulte também zsh :

(cd -P -- "$d" &&
  for file (**/*(ND.)) {
    dir=$file:h
    printf '%10s: %s\n' relative $file reldir $dir
  })

Acima, o . é equivalente a find -type f (somente arquivos regulares), enquanto D também inclui os ocultos, como find .

Como uma nota secundária, no caso geral:

c=$a$b; d=${c:${#a}}
[ "$b" = "$d" ] && echo yes

Não é garantido a saída "sim", porque os operadores ${#var} e ${var:offset} trabalham com caracteres , não bytes .

Por exemplo, em uma localidade UTF-8, ela não emitirá "sim" com esses valores de a e b :

a=$'St\xc3' b=$'\xa9phane'

Com esses, $c conteria meu primeiro nome ( Stéphane ) $a contém metade desse é caractere e $b a outra metade, ${#a} seria 3 (2 caracteres e 1 byte não formando um caracter válido, mas ainda é contado).

Então $d seria phane , não $'\xa9phane' .

No caso específico de d=$a/$b , ele deve estar OK, já que nenhum conjunto de caracteres geralmente disponível em localidades do sistema teria um caractere diferente de / que contém a codificação de / .

    
por 23.11.2017 / 14:33