execução de scripts shell Sincronizar
-
16-09-2019 - |
Pergunta
A versão de um href="http://www.sklav.com/?q=node/4" rel="nofollow noreferrer"> shell script converte um arquivo de áudio de FLAC para modificado formato MP3. O computador tem um CPU quad-core. O script é executado usando:
./flac2mp3.sh $(find flac -type f)
Isto converte os arquivos FLAC no diretório flac
(sem espaços em nomes de arquivos) para arquivos MP3 no diretório mp3
(ao mesmo nível que flac
). Se o arquivo de destino MP3 já existe, o script ignora o arquivo.
O problema é que às vezes duas instâncias do cheque roteiro para a existência do mesmo arquivo MP3 quase ao mesmo tempo, resultando em arquivos MP3 mutilados.
Como você executar os tempos roteiro múltiplas (ou seja, uma vez por núcleo), sem ter de especificar um conjunto de arquivos diferente em cada linha de comando, e sem substituir o trabalho?
Update - Corrida Minimal Condição
O script usa o seguinte mecanismo de bloqueio:
# Convert FLAC to MP3 using tags from flac file.
#
if [ ! -e $FLAC.lock ]; then
touch $FLAC.lock
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3"
rm $FLAC.lock
fi;
No entanto, isso ainda deixa uma condição de corrida.
Solução
O comando "lockfile" fornece o que você está tentando fazer para shell scripts sem a condição de corrida. O comando foi escrito pelo pessoal procmail especificamente para este tipo de propósito e está disponível na maioria dos sistemas BSD / Linux (como procmail está disponível para a maioria dos ambientes).
O teste torna-se algo como isto:
lockfile -r 3 $FLAC.lock
if test $? -eq 0 ; then
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3"
fi
rm -f $FLAC.lock
Como alternativa, você poderia fazer lockfile manter repetir indefinidamente, assim você não precisa testar o código de retorno, e em vez disso pode testar para o arquivo de saída para determinar se a flac prazo.
Outras dicas
Se você não tem lockfile
e não pode instalá-lo (em qualquer de suas versões - existem várias implementações) um mutex atômica robusto e portátil é mkdir
Se o diretório você tentar criar já existe, mkdir
falhará, assim você pode verificar para isso; quando a criação for bem sucedido, você tem a garantia de que nenhum outro processo cooperando está na seção crítica, ao mesmo tempo que o seu código.
if mkdir "$FLAC.lockdir"; then
# you now have the exclusive lock
: critical section
: code goes here
rmdir "$FLAC.lockdir"
else
: nothing? to skip this file
# or maybe sleep 1 and loop back and try again
fi
Para completar, talvez também olhar para flock
se você estiver em um conjunto de plataformas onde isso é feito de forma confiável disponível e precisam de uma alternativa performance para lockfile
.
Você poderia implementar bloqueio de arquivos FLAC que ele está trabalhando. Algo como:
if (not flac locked)
lock flac
do work
else
continue to next flac
enviar a saída para um arquivo temporário com um nome único, em seguida, renomeie o arquivo para o nome desejado.
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3.$$"
mv "$MP3.$$" "$MP3"
Se uma condição de corrida vazamentos através de seu sistema de bloqueio de arquivo a cada vez em quando, o resultado final ainda vai ser o resultado de um processo.
Para bloquear um processo de arquivo que você pode criar um arquivo com o mesmo nome com uma extensão .lock.
Antes de iniciar a codificação de verificar a existência do arquivo .lock e, opcionalmente, certifique-se a data da lockfile não é muito antiga (no caso das matrizes do processo). Se ele não existir, crie-antes do início da codificação e removê-lo após a codificação é concluída.
Você também pode reunem o arquivo, mas isso só realmente funciona em c onde você está chamando flock () e gravar o arquivo em seguida, fechando e desbloqueio. Para um script shell, você provavelmente estão chamando outro utilitário para fazer a escrita do arquivo.
Como sobre como escrever um Makefile?
ALL_FLAC=$(wildcard *.flac)
ALL_MP3=$(patsubst %.flac, %.mp3, $(ALL_FLAC)
all: $(ALL_MP3)
%.mp3: %.flac
$(FLAC) ...
Em seguida, faça
$ make -j4 all
No bash é possível opção set noclobber para a substituição de arquivo evitar.
help set | 'Noclobber | -C' egrep
Use uma ferramenta como Flom (bloqueio Manager Free) e simplesmente serializar seu comando como abaixo:
flom -- flac ....