Tendo algum problema ao usar “find -exec {} +”

4

Disclaimer: Eu sou um novato para Unix / Linux, mas estou ansioso para aprender! Eu tentei uma pesquisa neste stackexchange e li o man find , mas não consigo descobrir isso.

Eu quero usar o comando find ... -exec {} + para encontrar recursivamente todos os arquivos com uma extensão de arquivo específica e executar um comando na lista de arquivos. Existem aproximadamente 100k arquivos que eu preciso converter. O comando que estou executando aceita o nome do arquivo (ou uma lista de nomes de arquivos, por exemplo, f1 f2 f3 ) como um parâmetro, mas também preciso especificar parâmetros adicionais para executar o comando.

O que eu tentei até agora:

Isso funciona:

find . -iname "*.extension" -exec <command> {} <additional parameters> \;

Isso não parece funcionar:

find . -iname "*.extension" -exec <command> {} <additional parameters> +

Eu recebo a mensagem de erro, find: missing argument to '-exec' . Eu estou supondo que não posso especificar parâmetros adicionais após o {}

Algumas notas:

O comando em questão leva o nome do arquivo como o primeiro parâmetro e, em seguida, preciso designar alguns parâmetros adicionais, como o diretório de saída -o <outputDir> e as variáveis a serem extraídas dos arquivos -v <var1,var2,...> .

Estou executando isso no terminal no Ubuntu 12.04, se isso faz alguma diferença.

    
por ialm 11.06.2013 / 21:22

4 respostas

3
find . -iname "*.extension" -exec sh -c '
  exec <command> "$@" <additional parameters>' sh {} +
    
por 11.06.2013 / 22:27
1

Com o + , ele listará vários nomes de arquivos separados por espaços no lugar de {} (e será uma lista longa, pois você tem 100000 arquivos) em vez de apenas um único nome de arquivo. Sendo esse o caso, o {} é necessário para chegar no final do comando.

Veja a página find(1) man em -exec command {} + .

    
por 11.06.2013 / 21:43
1

Supondo que todos os diretórios e arquivos tenham nomes regulares, ou seja, sem espaços, sem linhas ou similares, isso deve funcionar mesmo com um grande número de arquivos:

find . -iname "*.extension" -exec sh -c '
command="<command>"
additionalParameters="<additional parameters>"
h=$(($#/2))
cmd="$command "
for i in $(seq 1 $h);do
        cmd="$cmd $(eval echo \$$i) "
done
cmd="$cmd $additionalParameters"
$cmd
shift $h
$command "$@" $additionalParameters' sh {} +

Fundamentação:

Ao usar a pontuação + , o find cria um comando o maior possível. Há duas limitações envolvidas, o número máximo de argumentos permitidos (deve ser 128k no Gnu / Linux) e o tamanho máximo da lista de argumentos (deve ser de 2 MB no Gnu / Linux). O problema é que o comando chamado requer argumentos extras (parâmetros adicionais). Adicioná-los ultrapassa o limite que leva ao "erro de muitos argumentos". Eu sugiro que o script divida a lista de parâmetros construídos em duas partes e execute dois comandos em vez de um por bloco, para que a adição de argumentos extras não exiba o problema.

    
por 12.06.2013 / 07:34
0

Você pode usar este script:

#! /bin/bash

cmd=echo

test $# -gt 2 || exit 2
num_trailing_args="$1"
[[ $num_trailing_args =~ ^(0|[1-9][0-9]*)$ ]] ||
  { echo "Illegal first argument ('${num_trailing_args}'); aborting"; exit 2; }
test $# -lt $((num_trailing_args+2)) &&
  { echo "Too few arguments; aborting"; exit 2; }
shift
trailing_args=()
for((i=0;i<num_trailing_args;i++)); do
        trailing_args[i]="$1"
        shift
done

"$cmd" "$@" "${trailing_args[@]}"

e, em seguida, use

find ... -exec args_change_script.sh 3 t1 t2 t3 {} +

O nome do comando não deve ser maior que o nome do script (só para ter certeza).

    
por 11.06.2013 / 22:21

Tags