Estou no Solaris 10 e testei o seguinte com ksh (88), bash (3.00) e zsh (4.2.1).
O código a seguir não produz nenhum resultado:
function foo {
echo "Hello World"
}
find somedir -exec foo \;
A descoberta corresponde a vários arquivos (como mostrado substituindo -exec ...
por-print
), e a função funciona perfeitamente quando chamada fora da find
chamada.
Aqui está o que a man find
página diz sobre-exec
:
comando -exec True se o comando executado retornar um valor zero como status de saída. O fim de comando deve ser pontuado por um escape ponto e vírgula (;). Um argumento de comando {} é substituído pelo nome do caminho atual. Se o o último argumento para -exec é {} e você especifique + em vez do ponto e vírgula (;), o comando é chamado menos vezes, com {} substituído por grupos de nomes de caminho. E se qualquer invocação do comando retorna um valor diferente de zero como status de saída, localize retorna um status de saída diferente de zero.
Eu provavelmente poderia sair fazendo algo assim:
for f in $(find somedir); do
foo
done
Mas tenho medo de lidar com problemas de separador de campos.
É possível chamar uma função shell (definida no mesmo script, não vamos nos preocupar com problemas de escopo) de uma find ... -exec ...
chamada?
Eu tentei com ambos /usr/bin/find
e /bin/find
e obteve o mesmo resultado.
export -f foo
PATH
. Como alternativa, usesh -c '...'
e ambos definem AND executam a função no...
bit. Pode ajudar a entender as diferenças entre funções e scripts .Respostas:
A
function
é local para um shell, então você precisafind -exec
gerar um shell e ter essa função definida nesse shell antes de poder usá-lo. Algo como:bash
permite exportar funções através do ambienteexport -f
, para que você possa fazer (no bash):ksh88
temtypeset -fx
que exportar a função (não pelo ambiente), mas isso só pode ser usado por menos scripts executados pelo she-bangksh
, por isso não comksh -c
.Outra opção é fazer:
Ou seja, use
typeset -f
para despejar a definição dafoo
função dentro do script embutido. Observe que, sefoo
usar outras funções, você também precisará despejá-las.fonte
ksh
oubash
no-exec
comando? Eu entendo a primeira, mas não a segunda ocorrência.bash -c 'some-code' a b c
,$0
éa
,$1
éb
..., então se você quiser$@
ser,a, b, c
precisa inserir algo antes. Como$0
também é usado ao exibir mensagens de erro, é uma boa ideia usar o nome do shell ou algo que faça sentido nesse contexto.Isso nem sempre é aplicável, mas quando é, é uma solução simples. Defina a
globstar
opção (set -o globstar
no ksh93,shopt -s globstar
no bash ≥4; está ativado por padrão no zsh). Em seguida, use**/
para corresponder o diretório atual e seus subdiretórios recursivamente.Por exemplo, em vez de
find . -name '*.txt' -exec somecommand {} \;
, você pode executarEm vez de
find . -type d -exec somecommand {} \;
, você pode executarEm vez de
find . -newer somefile -exec somecommand {} \;
, você pode executarQuando
**/
não funciona para você (porque o seu shell não tê-lo, ou porque você precisa de umafind
opção que não tem um análogo shell), definir a função nofind -exec
argumento .fonte
globstar
opção na versão do ksh (ksh88
) que estou usando.dtksh
(ksh93 com algumas extensões X11), mas uma versão antiga e possivelmente parte de um pacote opcional em que o CDE é opcional.find
que exclui arquivos de ponto e não desce para dotdirs e classifica a lista de arquivos (os quais podem ser endereços no zsh por meio de qualificadores de globbing). Também com**/*
, ao contrário./**/*
, nomes de arquivos podem começar com-
.Use \ 0 como delimitador e leia os nomes de arquivos no processo atual a partir de um comando gerado, da seguinte maneira:
Oque esta acontecendo aqui:
read -d ''
lê até o próximo \ 0 byte, para que você não precise se preocupar com caracteres estranhos nos nomes de arquivos.-print0
usa \ 0 para finalizar cada nome de arquivo gerado em vez de \ n.cmd2 < <(cmd1)
é o mesmo quecmd1 | cmd2
exceto que o cmd2 é executado no shell principal e não em um subshell./dev/null
para garantir que ela não seja lida acidentalmente no canal.$filename
é citado para que o shell não tente dividir um nome de arquivo que contenha espaço em branco.Agora,
read -d
e<(...)
estão no zsh, bash e ksh 93u, mas não tenho certeza das versões anteriores do ksh.fonte
se você deseja que um processo filho, gerado em seu script, use uma função shell predefinida, é necessário exportá-lo com
export -f <function>
NOTA:
export -f
é específico do bashpois apenas um shell pode executar funções do shell :
EDIT: essencialmente o seu script deve se parecer com isso:
fonte
export -f
é um erro de sintaxe emksh
e imprime a definição da função na tela emzsh
. Em todos osksh
,zsh
ebash
, não resolve o problema.find / -exec /bin/bash -c 'function' \;
bash
. Obrigado!{}
o código do shell! Isso significa que o nome do arquivo é interpretado como código shell por isso é muito perigoso