Eu tenho um comando (não echo
!) que desejo executar, que segue um caminho absoluto e um caminho relativo.
Como obtenho esses dois argumentos?
Tentar:
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 excessivos)
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
Responder1
Export d
, então ele estará disponível em seu bash
script embutido. Você também não precisa bash
de nada aqui. O seu (espero que seja mais fino/mais rápido) sh
também funcionaria. Além disso, você não precisa executar um shell por arquivo. Você pode passar mais arquivos para seu script embutido com a -exec cmd {} +
variante:
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 {} +
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 tornaria os argumentos do comando passados para sh
mais curtos, permitindo find
passar mais argumentos para sh
.
Observe que não há nada específico do GNU no seu find
comando nem no meu. Isso deve funcionar em qualquer implementação compatível com POSIX find
, não apenas na GNU. A única parte não POSIX na sua pergunta foi obviamente bash
e o ${1:offset}
operador que é um operador Korn Shell, não em POSIX sh
.
Para uma pesquisa recursiva de arquivo 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
's -type f
(apenas arquivos regulares), mas D
também inclui arquivos ocultos, como find
faz.
Como observação lateral, no caso geral:
c=$a$b; d=${c:${#a}}
[ "$b" = "$d" ] && echo yes
Não é garantido que a saída seja "sim", porque os operadores ${#var}
e ${var:offset}
trabalham compersonagens, nãobytes.
Por exemplo, em um código de idioma UTF-8, não seria gerado yes com estes valores de a
e b
:
a=$'St\xc3' b=$'\xa9phane'
Com eles, $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 caractere válido, mas ainda contado).
Assim $d
seria phane
, não $'\xa9phane'
.
Porém, no caso específico d=$a/$b
, deve estar tudo bem, já que nenhum conjunto de caracteres geralmente disponível nas localidades do sistema teria um caractere diferente /
daquele que contém a codificação de /
.