0. O script quer fazer algo assim.
O script mostrado na sua pergunta tenta enumerar os arquivos e verificar se eles são JPEGs, mas não de forma confiável. Ele tenta passar todos os caminhos para file
em uma única execução e extrai os nomes e tipos de arquivos da saída de file
, que é razoável , pois pode ser mais rápido do que executar file
novamente para cada arquivo. Mas para fazer isso corretamente, você precisa ter cuidado sobre como os caminhos são passados para file
, como file
delimita sua saída e como você consome essa saída. Você pode usar isto:
#!/bin/bash
find . -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
case "$mimetype" in image/jpeg)
# Bash placed the filename in "$REPLY" -- put commands that use it here.
# You can have as many commands as you want before the closing ";;" token.
;;
esac
done
Essa é uma das várias maneiras corretas. (Ele não precisa definir IFS=
; veja abaixo.)% Co_de% com find
passa vários argumentos de caminho para +
e só o executa quantas vezes forem necessárias para processar todos eles , geralmente apenas uma vez. O crédito vai para AFSHIN para a idéia de passando file
para --mime-type
para obter o tipo MIME, que contém as informações que você realmente deseja e é fácil de analisar.
Uma explicação detalhada segue. Eu usei a tarefa específica de compactação JPEG como exemplo. Isso é o que o script que você mostrou é, e file
tem algumas esquisitices que devem ser consideradas ao decidir como melhorar esse script. Se você quiser apenas ver um script que execute lepton
em cada arquivo JPEG, você pode pular para a seção 7. Juntando tudo .
O termo caminho tem várias definições. Nessa resposta, eu uso para significar nome do caminho .
1. Instalando lepton
O script que você mostrou se destina a percorrer uma hierarquia de diretórios, localizar imagens JPEG e processá-las com o compressor JPEG sem perdas lepton
. Para a motivação principal da sua pergunta, o comando pode não ser realmente importante, mas comandos diferentes têm uma sintaxe diferente. Alguns comandos aceitam vários nomes de arquivos de entrada para uma única execução. A maioria aceita lepton
para indicar o final das opções. Usarei --
como meu exemplo. O comando lepton
não aceita vários nomes de arquivos de entrada e não reconhece lepton
.
Para usar --
, instale-o primeiro. É empacotado oficialmente para o Ubuntu 17.04 e posterior ( lepton
). Para lançamentos anteriores do Ubuntu, ou para usar uma versão mais recente do que a que foi lançada para o seu lançamento, clone seu repositório sudo apt install lepton
( git
) e construa a fonte conforme instruído no README . Ou você pode ser capaz de encontre um PPA .
Dependendo de como você o instala, git clone https://github.com/dropbox/lepton.git
pode estar em lepton
, /usr/bin
ou em outro lugar. Provavelmente você vai querer em algum lugar em /usr/local/bin
; então você pode executá-lo como $PATH
. O script que você mostrou usa caminhos absolutos para lepton
e os utilitários padrão lepton
e mv
, mas não para os outros utilitários padrão rm
, file
, find
e grep
. (Este é o Bash, então cut
- sem esse script de qualquer maneira - é um shell embutido . echo
é sempre construídos .) Embora essa não seja uma das falhas sérias do script, não há razão discernível para tal inconsistência. A menos que você esteja escrevendo um script para tolerar que não tenha exit
definido de maneira sensata - nesse caso, você deve usar caminhos absolutos para todos os comandos externos - sugiro usar caminhos relativos para comandos padrão e aqueles que você instalou.
2. Executando $PATH
Cuidados e informações gerais
Eu testei com o lepton v1.0-1.2.1-104-g209463a (do Git). lepton
foi lançado em julho de 2016 então eu acho que a sintaxe atual continuará funcionando Mas versões futuras podem adicionar recursos. Se você estiver lendo este ano, poderá verificar se lepton
adicionou suporte a tarefas que antes exigiam scripts.
Por favor, tenha cuidado com os argumentos da linha de comando que você passa . Por exemplo, tentei executar lepton
com lepton
como o primeiro argumento e -verbose
como o segundo. Ele interpretou art.jpg
como um nome de arquivo de entrada e encerrou com um erro, mas não antes de truncar -verbose
- que interpretou como um nome de arquivo de saída - para baixo para zero bytes. Felizmente eu tive um backup!
Você pode passar zero, um ou dois caminhos para art.jpg
. Em todos os casos, ele examina seu arquivo de entrada ou fluxo para ver se ele contém dados JPEG ou Lepton. JPEG é compactado para Lepton; Lepton é descomprimido para JPEG. lepton
removerá e adicionará extensões de arquivo, mas não as usará para decidir o que fazer.
Nomes de arquivo zero - lepton
lê de stdin e escreve para stdout .
Assim, lepton -
é uma maneira de ler lepton - < infile > outfile
e gravar em infile
, mesmo que seus nomes comecem com outfile
(como as opções ). Mas o método que vou usar passa por caminhos que começam com -
, então não vou ter que me preocupar com isso.
Um nome de arquivo - .
lê lepton infile
e nomeia seu próprio arquivo de saída.
É assim que o script que você mostrou usa infile
.
Se o conteúdo de lepton
se parecer com um JPEG, infile
gerará um arquivo Lepton; se seu conteúdo se parece com um arquivo Lepton, lepton
produz um JPEG. lepton
decide como deseja nomear seu arquivo de saída removendo uma extensão de lepton
, se houver, e adicionando uma extensão infile
ou .jpg
dependendo do tipo de arquivo está criando. Mas ele não usa a extensão que está removendo (se houver) para inferir o tipo de arquivo em que está operando.
Considera o último .lep
e qualquer coisa depois dele como uma extensão. Se .
for infile
, você receberá a.b.c
ou a.b.lep
. Se o nome do arquivo começar com a.b.jpg
sem nenhum outro .
s, .
ainda considera isso como uma extensão: de um JPEG chamado lepton
, você obtém .abc
. Apenas .lep
no nome do arquivo - não nos nomes dos diretórios - aciona isso, portanto, de um arquivo Lepton .
você obtém x/fo.o/abc
(que você quer), não x/fo.o/abc.jpg
(o que seria ruim).
Se o nome do arquivo de saída obtido dessa forma nomear um arquivo existente, x/fo.jpg
s serão adicionados ao final, após a extensão, até que não seja adicionado, e o nome com sublinhados adicionados será usado: _
, abc.lep
, abc.lep_
, etc, abc.lep__
, xyz.jpg
, xyz.jpg_
, etc.
Isso funciona melhor quando seus arquivos são nomeados de uma maneira sensata.
Remover e adicionar extensões automaticamente e adicionar sublinhados evita um problema que você teria de gerenciar, evitando a perda de dados quando o arquivo de saída já existir. Mas também expõe o que pode ser uma profunda falha de design no script que você mostrou. Se os seus arquivos são nomeados de forma sensata, então todos os seus arquivos JPEG terminam em xyz.jpg__
ou .jpg
(talvez em maiúsculas), e nenhum arquivo não-JPEG é assim chamado. Mas você não precisa examinar os arquivos com .jpeg
para descobrir quais são JPEGs!
Assim, a premissa do script que você mostrou é que os arquivos podem não ser nomeados de forma razoável. É sempre ruim para um script se comportar errado ou inesperadamente em nomes de arquivos contendo espaços, file
e outros caracteres especiais. Portanto, seu comportamento de dividir em espaços em branco e expandir globs (a substituição de comando externa sem aspas, destinada apenas a dividir nomes de arquivos separados, faz isso) é especialmente ruim. Veja a excelente resposta do Byte Commander para detalhes. Esta é provavelmente a pior falha no script que você mostrou.
Mas também vale a pena considerar o que acontece com nomes de arquivos cujo último *
não conceitualmente inicia uma extensão de arquivo. Suponha que .
tenha quatro arquivos, todos JPEGs: Pictures
, 01. Milan wide-angle sunset
, 01. Milan wide-angle sunset highres
e 02. Kyle birthday party prep - blooper cakes
. Então, 03. The subtle found art of unopened expired paint cans with peeling labels
cria for f in ~/Pictures/0*; do lepton "$f"; done
, 01.lep
, 01.lep_
e 02.lep
- provavelmente não é o que você deseja.
Se você tiver JPEGs não denominados 03.lep
ou talvez .jpg
, a melhor abordagem geral é renomeá-los dessa maneira e investigar quaisquer conflitos de nomenclatura que surgirem durante esse processo. Mas isso está além do escopo desta resposta.
Aqueles problemas de renomeação acontecem com JPEGs não nomeados como JPEGs, não não-JPEGs nomeados como JPEGs. Mesmo assim, pode haver uma solução melhor. Se o problema for .jpeg
de arquivos do macOS e você não quiser excluí-los, apenas exclua arquivos com um ._
(ou mesmo um ._
) inicial.Ainda assim, passar apenas um caminho para .
evita a perda de dados (devido às suas regras de lepton
de anexação); Se a meta principal for excluir não-JPEGs, a idéia básica é sólida, mesmo que a implementação precise ser corrigida.
Então, usarei a sintaxe _
de um caminho . Mas qualquer um que considere a automação de lepton infile
como essa em arquivos com nomes estranhos deve lembrar que os arquivos lepton
gerados podem ser nomeados de maneiras que não revelam os nomes dos arquivos de entrada.
Dois nomes de arquivos - .lep
faz exatamente o que você espera.
Mas só porque você espera que isso não seja a coisa certa a fazer.
Como nas outras formas de executar lepton infile outfile
, lepton
determina se lepton
é um JPEG a ser compactado ou um arquivo Lepton a ser descompactado examinando seu conteúdo. Se infile
for um JPEG, infile
gravará um arquivo Lepton chamado lepton
; Se outfile
for um arquivo Lepton, infile
gravará um arquivo JPEG chamado lepton
. Com essa sintaxe de dois caminhos, outfile
não altera o nome do arquivo de saída especificado de nenhuma maneira. Não adiciona ou remove extensões nem adiciona lepton
s para resolver conflitos de nomenclatura. Se _
já existir, ele será sobrescrito.
Você pode querer isso, mas se não, e você usar esta sintaxe, você terá que resolver o problema fazendo seu script ajustar os nomes dos arquivos de saída. Você pode ser capaz de fazer isso de uma maneira que lhe sirva melhor do que o esquema do próprio outfile
quando executado com apenas um argumento de caminho. Mas não tentarei adivinhar suas necessidades e preferências específicas; Vou usar apenas a sintaxe de um caminho.
3. Passando Múltiplos Caminhos De lepton
para find
O script que você mostrou tenta usar file
para passar um caminho por argumento para file $(find ./ )
executando file
em substituição de comandos . Isso geralmente não funciona, porque find
divide no espaço em branco, que os nomes de arquivo podem conter. É comum que arquivos - especialmente imagens! - e pastas tenham espaços em seus nomes. O script que você mostrou trata um caminho $(find ./ )
como dois caminhos, ./abc/foo bar.jpg
e ./abc/foo
. Na melhor das hipóteses, não existe; se o fizerem, você involuntariamente opera na coisa errada. E o caminho original não será processado de todo.
Embora a amplitude desse problema possa ser reduzida pela definição de bar.jpg
, então divisão de palavras é realizado apenas entre linhas ( IFS=$'\n'
representa um caracter newline ), essa não é uma boa solução . Além de ser estranho, ainda pode falhar, pois os nomes de arquivos e diretórios podem conter novas linhas. Eu aconselho contra a nomeação de arquivos ou diretórios com eles, exceto para testar programas ou scripts de bugs. Mas esses nomes podem ser criados, incluindo por acaso onde você não os espera. Os únicos caracteres que um nome de arquivo não pode conter são o separador de caminho \n
e o caractere nulo . O caractere nulo é, portanto, o único que não pode aparecer em um caminho e a única opção segura para delimitar listas de caminhos arbitrários. É por isso que /
tem uma ação find
e -print0
tem uma opção xargs
.
Isso pode ser feito corretamente com -0
, mas você não precisa de um terceiro utilitário para passar caminhos de find . -print0 | xargs -0 ...
para find
. file
' find
action é suficiente. Argumentos após -exec
criam o comando para execução, até -exec
ou \;
. +
executa um comando uma vez por arquivo, enquanto find ... -exec ... \;
passa o comando como muitos caminhos possíveis por execução, o que geralmente é mais rápido. Normalmente, todos os argumentos se encaixam e o comando é executado apenas uma vez. Em casos raros, a linha de comando seria muito longa e find ... -exec ... +
executará o comando mais de uma vez. Portanto, a forma find
é segura apenas para executar comandos que (a) executam seus argumentos de caminho no final e (b) funcionam da mesma maneira em uma execução com vários nomes de arquivos como fazem em corridas separadas.
+
é um exemplo de um comando que não deve ser executado usando o lepton
form de +
porque ele não aceita vários nomes de arquivos de origem. A primeira seria a entrada, a segunda seria a saída e outras seriam excessivas. Mas muitos comandos do fazem a mesma coisa quando são executados uma vez com vários argumentos, como quando são executados várias vezes com um argumento, e -exec
é um deles .
Este comando irá gerar a tabela:
find . -exec file --mime-type -r0F '' {} +
file
substitui o argumento find
por um caminho quando invoca {}
e substitui file
pelo número de argumentos de caminho adicionais que couberem.
As opções +
passadas para --mime-type -r0F ''
são explicadas abaixo.
Algumas pessoas citação find
, por exemplo, {}
. Não há problema em fazê-lo , mas nem Bash nem outros shells estilo Bourne exigem isso. Bash e alguns outros shells suportam expansão de brace , mas um par vazio de chaves não é expandido. Eu escolho não para citar '{}'
, à luz do equívoco que citando {}
impede que {}
execute divisão de palavras . Mesmo que seu shell tenha exigido find
a ser citado, isso ainda não teria nada a ver com a divisão de palavras, porque {}
nunca faz isso (se você quisesse a divisão de palavras, teria que informar find
to find
a shell). co_de% não sabe dizer se você escreveu -exec
ou find
- o shell transforma {}
em '{}'
(durante quote remoção ) antes de passá-la para '{}'
.
4. Emitindo uma tabela ⟨Path, File Type⟩ utilizável com {}
O problema
O motivo pelo qual devo passar algumas opções para find
- e não posso usar apenas file
- é que a tabela file
gerada por padrão é ambígua:
01. Milan wide-angle sunset: JPEG image data, JFIF standard 1.01, resolution (DPI), density 1x1, segment length 16, baseline, precision 8, 1400x1400, frames 3
02. Kyle birthday party prep - blooper cakes: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 512x512, frames 3
first line
second line: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 500x500, frames 3
Essas três linhas parecem quatro; um nome de arquivo contém uma nova linha. Os nomes de arquivo também podem conter dois pontos, portanto, nem sempre ficará claro onde o nome do arquivo termina. Exemplos mais confusos do que os mostrados acima são possíveis.
A coluna de descrição também tem muito mais informações do que precisamos. Byte Commander explica uma razão find . -exec file {} +
ing para file
em cada linha inteira retorna resultados errados: um arquivo não-JPEG com grep
em seu nome dá um falso positivo. (O ponto de verificar o tipo é que você não pode confiar no nome, então isso é um erro bastante autodestrutivo no script que você mostrou.) Mas mesmo quando você sabe que está procurando na coluna de descrição, pode ainda contém JPEG
, mesmo que não seja o tipo:
$ touch empty.JPEG # not a JPEG
$ gzip -k empty.JPEG
$ file empty.JPEG*
empty.JPEG: empty
empty.JPEG.gz: gzip compressed data, was "empty.JPEG", last modified: Mon Aug 28 16:37:56 2017, from Unix
A resposta do Byte Commander resolveu isso (a) passando a opção JPEG
para JPEG
, fazendo com que omita os caminhos, -b
separador e espaços na frente do tipo, então (b) usando file
para verificar se a descrição começa > em> com :
(a grep
âncora no padrão JPEG
faz isso). Isso funciona se você acompanhar os caminhos passados para ^
- não é um problema para o método Byte Commander, que executou ^JPEG image data,
separadamente para cada caminho, de qualquer maneira.
A solução
Eu preciso usar uma solução diferente, porque meu objetivo é analisar os caminhos e tipos da saída de file
, para que file
não precise ser executado separadamente para cada arquivo. Felizmente, o file
no Ubuntu tem muitas opções . Eu uso file
:
-
file
imprime um tipo MIME em vez de uma descrição detalhada. Isso é tudo que eu preciso, e então posso apenas fazer uma correspondência exata contra a coisa toda. Para um JPEG, file --mime-type -r0F '' paths
mostra --mime-type
na coluna de descrição. (Veja também resposta da AFSHIN .)
- De acordo com
file --mime-type
, image/jpeg
faz com que caracteres não imprimíveis não sejam para ser substituído por escapes octal como man file
. Acredito que, caso contrário, precisaria adicionar uma etapa para converter essas sequências de volta para os caracteres reais, o que provavelmente não pode ser feito de forma confiável - e se essa sequência aparecer literalmente em um nome de arquivo? ( -r
não escapam file
3
como \
.) Digo "acredito" porque não consegui obter \
para imprimir essa sequência de escape, e Não tenho certeza se realmente faz isso na coluna do nome do arquivo. De qualquer forma, file
está seguro aqui.
-
-r
é a opção chave aqui. Sem ela, esse método não funcionaria de maneira confiável. Faz com que -0
imprima um caractere nulo - o caractere que nunca é permitido em caminhos, porque é normalmente usado para marcar as extremidades de strings em programas em C - imediatamente após o nome do arquivo. Isso marca a quebra, em cada linha, entre as duas colunas da tabela.
-
file
faz -F ''
imprimir nada ( file
é um argumento vazio) em vez de ''
. O cólon não é confiável (pode aparecer em nomes de arquivo) e não tem nenhum benefício aqui, pois um caractere nulo já está sendo impresso para indicar o final da coluna de caminho e o início da coluna de descrição.
Para tornar :
run find
, uso file --mime-type -r0F '' paths
. A ação -exec file --mime-type -r0F '' {} +
de find
substitui -exec
pelos caminhos.
5. Consumindo a Mesa
Eu criei a tabela dessa maneira:
find . -exec file --mime-type -r0F '' {} +
Como detalhado acima, isso coloca um caractere nulo após cada caminho. Seria útil se a descrição também fosse terminada em null, mas {} +
não faria isso - a descrição sempre termina com uma nova linha. Portanto, devo ler alternadamente até um caractere nulo, depois presumir que há mais texto e lê-lo até uma nova linha.Eu devo fazer isso para cada arquivo e parar quando nada for deixado.
Lendo cada linha
Essa combinação - leia o texto que pode conter uma nova linha até um caractere nulo, depois leia o texto que não pode conter uma nova linha até uma nova linha - não é como os utilitários comuns do Unix são normalmente usados. A abordagem que vou tomar é canalizar a saída de file
para um loop. Cada iteração do loop lê uma única linha da tabela usando o find
shell embutido duas vezes, com diferentes opções.
Para ler o caminho , eu uso:
read -rd ''
-
read
is -r
é a única opção padrão e você deve quase sempre usá-la. Sem ele, as barras invertidas escapam como read
da entrada e são traduzidas nos caracteres que elas representam. Nós não queremos isso.
- Normalmente,
\n
lê até ver uma nova linha. Para ignorar novas linhas e parar em um caractere nulo, eu uso a opção read
, que o Bash fornece, para especificar um caractere diferente. Para um caractere nulo, passe o argumento vazio -d
.
- Eu já estou usando uma extensão Bash (a opção
''
), então também posso usar o comportamento padrão do Bash quando nenhum nome de variável for passado para -d
. Ele coloca tudo o que lê - exceto o caractere de término - na variável especial read
. Normalmente $REPLY
retira espaço em branco ( read
caracteres) do início e do final da entrada, e é comum escrever $IFS
para evitar isso. Ao ler implicitamente para IFS= read ...
no Bash, isso não é necessário.
Para ler a descrição , eu uso:
read -r mimetype
- Nenhuma barra invertida deve aparecer no tipo MIME, mas é recomendável passar
$REPLY
para -r
, a menos que deseje read
escapes translated.
- Desta vez, eu am especificando explicitamente o nome de uma variável. Chame do que você gosta. Eu escolhi
\
.
- Desta vez, a ausência de
mimetype
para evitar que o espaço em branco inicial e final seja removido é significativo. Eu quero isso removido. Isso elimina os espaços desde o início da descrição que IFS=
grava para tornar a tabela mais legível quando é mostrada em um terminal.
Compondo o Loop
O loop deve continuar enquanto houver outro caminho a ser lido. O comando find
retorna verdadeiro (na programação shell isso é zero, ao contrário de quase todas as outras linguagens de programação) quando lê algo com sucesso, e falso (na programação shell, qualquer valor diferente de zero) quando não o faz. Portanto, o idioma comum read
é útil aqui. Eu pipe ( while read
) a saída de |
- que é a saída de um ou (raramente) mais find
comandos - para o loop file
.
find . -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
# Commands using "$REPLY" and "$mimetype" go here.
done
Dentro do loop, eu leio o resto da linha para obter a descrição ( while
). Eu não me incomodo em verificar se isso foi bem sucedido. read -r mimetype
só deve produzir linhas completas mesmo que encontre erros . ( file
envia mensagens de erro e aviso para o erro padrão , então elas não aparecerá no pipeline para corromper a tabela.) Você deve poder confiar nisto.
Se você quiser verificar se file
foi bem-sucedido, use read -r mimetype
. Ou você pode incluí-lo na condição if
do loop:
find . -exec file --mime-type -r0F '' {} + |
while read -rd '' && read -r mimetype; do
# Commands using "$REPLY" and "$mimetype" go here.
done
Você pode ver que eu também divido a linha superior para facilitar a leitura. (Não é necessário while
para dividir em \
.)
Testando o loop
Se você quiser testar o loop antes de prosseguir, pode colocar este comando em (ou em vez de) o comentário |
:
printf '[%s] [%s]\n\n' "$REPLY" "$mimetype"
A saída do loop é algo como isso, dependendo do que você tem no diretório (e deixei de lado a maioria das entradas, por questões de brevidade):
[.] [inode/directory]
[./stuv] [inode/x-empty]
[./ghi
jkl] [inode/x-empty]
[./fo.o/abc
def ] [image/jpeg]
[./fo.o/wyz.lep] [application/octet-stream]
[./fo.o/wyz] [image/jpeg]
Isso é apenas para ver se o loop funciona corretamente. Colocar as entradas da tabela em # Commands...
[
desta forma não ajudaria o script a fazer o que ele precisa fazer, pois os caminhos podem conter ]
, [
e novas linhas consecutivas.
6. Usando o caminho extraído e o tipo de arquivo
Em cada iteração do loop, ]
contém o caminho e "$REPLY"
contém a descrição do tipo. Para descobrir se "$mimetype"
nomeia um arquivo JPEG, verifique se "$REPLY"
é exatamente "$mimetype"
.
Você pode comparar strings usando image/jpeg
e if
/ [
(ou test
) com [[
. Mas eu prefiro =
:
find -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
case "$mimetype" in image/jpeg)
# Put commands here that use "$REPLY".
;;
esac
done
Se você quisesse apenas mostrar os caminhos dos JPEGs no mesmo formato acima - para ajudar a testar caminhos com novas linhas - a declaração case
... case
inteira poderia ser:
case "$mimetype" in image/jpeg) printf '[%s]\n\n' "$REPLY";; esac
Mas o objetivo é executar esac
em cada arquivo JPEG. Para fazer isso, use:
case "$mimetype" in image/jpeg) lepton "$REPLY";; esac
7. Juntando Tudo
Adicionando o comando lepton
e uma linha hashbang para executá-lo com o Bash, aqui está o script completo :
#!/bin/bash
find . -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
case "$mimetype" in image/jpeg) lepton "$REPLY";; esac
done
lepton
informa o que está fazendo, mas não mostra nomes de arquivo. Este script alternativo imprime uma mensagem com cada caminho antes de executar lepton
:
#!/bin/bash
find . -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
case "$mimetype" in image/jpeg)
printf '\nProcessing "%s":\n' "$REPLY" >&2
lepton "$REPLY"
esac
done
Eu imprimi as mensagens para erro padrão ( lepton
), já que é onde >&2
envia suas próprias mensagens. Dessa forma, a saída permanece toda unida quando canalizada ou redirecionada. Executar esse script produz uma saída como essa (mas mais se você tiver mais de dois JPEGs):
Processing "./art.jpg":
lepton v1.0-1.2.1-104-g209463a
6777856 bytes needed to decompress this file
56363 86007
65.53%
2635854 bytes needed to decompress this file
56363 86007
65.53%
Processing "./fo.o/abc
def ":
lepton v1.0-1.2.1-104-g209463a
6643508 bytes needed to decompress this file
36332 46875
77.51%
2456117 bytes needed to decompress this file
36332 46875
77.51%
A repetição em cada sub-rotina - que também aparece quando você executa lepton
sem imprimir nomes de arquivos - é porque lepton
verifica se seus arquivos de saída podem ser descompactados corretamente.
O script que você mostrou tinha lepton
no final. Você pode fazer isso se quiser. Isso faz com que o script sempre relate o sucesso. Caso contrário, o script retornará o status de saída do último comando executado - o que é provavelmente preferível. De qualquer forma, ele pode relatar sucesso mesmo se exit 0
, find
ou file
encontrar problemas, se o comando último lepton
tiver sido bem-sucedido. Você pode, é claro, expandir o script com um código de tratamento de erros mais sofisticado.
8. Talvez você queira os caminhos, também
Se você deseja gerar uma lista de caminhos separados da própria saída de lepton
, aproveite o comportamento de gravação de lepton
para erro padrão imprimindo os caminhos para saída padrão . Nesse caso, você provavelmente deseja imprimir apenas os caminhos e não uma mensagem "Processando". Opcionalmente, você pode querer terminar os caminhos com caracteres nulos em vez de novas linhas, assim você pode processar a lista sem quebrar caminhos que contenham novas linhas.
#!/bin/bash
case "" in
-0) format='%sxargs -0 printf '[%s]\n\n' < out
';;
*) format='%s\n';;
esac
find . -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
case "$mimetype" in image/jpeg)
printf "$format" "$REPLY"
lepton "$REPLY"
esac
done
Quando você executa esse script, pode passar o sinal lepton
para emitir caracteres nulos em vez de novas linhas. Esse script não faz o processamento de opção no estilo Unix: ele apenas verifica o argumento primeiro que você passa; passar a bandeira repetidamente no mesmo argumento ( -0
) não funciona; e nenhuma mensagem de erro relacionada à opção é gerada. Essa limitação é por brevidade, e porque você provavelmente não precisa de nada mais sofisticado, pois o script não suporta argumentos que não sejam de opção e -00
é a única opção possível.
No meu sistema, chamei esse script de -0
e coloquei em jpeg-lep3
, depois executei ~/source
, que imprimiu apenas a saída de ~/source/jpeg-lep3 -0 > out
para o meu terminal. Se você fizer algo assim, poderá testar se os caracteres nulos foram escritos corretamente entre os caminhos usando:
%pre%