O apresentador marcou este programa como "Limpo".
Recentemente, tive uma experiência em que as ferramentas UNIX provaram ser muito úteis. Um parente tinha um velho celular com Android que parou de se conectar à rede do provedor e comprou um novo para substituí-lo. Assumi a tarefa de tentar copiar os arquivos (que consistiam apenas em fotos e vídeos) do velho telefone.
O software do Google estava desesperado para me convencer a fazer o upload de tudo para a nuvem, mas eu não estava interessado. Ele ofereceu a opção de copiar os arquivos para um cartão SD, mas falhou em tentativas repetidas de fazer isso. A opção que tentei em seguida foi transferir os arquivos para outro dispositivo via Bluetooth - essa funcionou, embora fosse lenta e só conseguisse enviar cerca de 100 arquivos de cada vez.
Eles foram para o meu laptop sem problemas, mas o problema com esse método era que todas as datas dos arquivos estavam definidas para o momento em que foram transferidos. Não sou muito familiarizado com como os aplicativos móveis gerenciam metadados, mas suponho que eles usem as datas dos arquivos para organizar fotos por data. Felizmente,os nomesde cada arquivo incluíam a data e a hora em que foram criados. Reconheci que poderia escrever um pouco de script de shell para analisar os nomes dos arquivos e definir as datas dos arquivos de acordo.
Embora houvesse mais de 800 arquivos, a boa notícia é que havia apenas três categorias diferentes de nomes de arquivos, então a lógica para extrair as informações necessárias era relativamente simples. Cada arquivo tinha oito dígitos numéricos representando a data e seis dígitos representando a hora. Definitivamente, seria uma opção criar um analisador mais sofisticado que pudesse lidar com uma variedade de nomes de arquivos, mas optei pelo caminho mais fácil e apenas tratei esses três casos. Outro aspecto positivo foi que nenhum dos nomes de arquivos continha espaços, o que me permitiu ser menos cuidadoso ao usá-los em comandos. Não precisei me preocupar com fusos horários porque o meu laptop estava na mesma zona horária que o telefone - também, se uma hora estivesse fora por algumas horas, não faria diferença prática.
Exemplos dos três diferentes tipos de nomes de arquivos com os quais tive que lidar, rotulados com os valores relevantes: YYYY=ano, MM=mês, DD=dia, hh=hora, mm=minuto, SS=segundo.
00001IMG_00001_BURST20250525140124.jpg IMG_20220223_124023.jpg VID_20221017_095024.mp4 YYYYMMDD hhmmSS - 20191224_195939.jpg - 20161021_122620-1.jpg - 20191130_134317_Burst01.jpg - 20200129_223612_010.jpg YYYYMMDD hhmmSS
Consideri:A tradução do texto fornecido para o português brasileiro é:
"awk"Como uma opção (ver )Comentário do Whiskeyjack sobre o episódio 4657 do HPREmbora eu tenha descoberto que ele não tem uma maneira integrada de alterar as datas de arquivo, então o coloquei de lado. Não se preocupe, eu...
willVou voltar a isso mais tarde.
Minha abordagem foi usar umconstruto de comandoif-then para escolher como tratar as três categorias de nomes de arquivos. Para acondição, passei o nome do arquivo para o comandogrep -qcom uma expressão regular apropriada para testar se corresponde. O-q-qUma opção para...Busca por padrão...O que causa que ele não produza nada — ele retorna um status de saída zero se houver uma correspondência e um status maior que zero se não houver. Então, há uma...Se (elif)Uma declaração...Busca silenciosa por...Um teste para a segunda categoria de nomes de arquivos. Finalmente, um...Caso contrário (else)A declaração é seguida pelo comando para executar para todos os outros nomes de arquivos. O todo é embrulhado em um loop `for` que percorre todos os arquivos no diretório atual.O comando `for`O loop
O comando `touch`
O comando `touch`, quando usado com a opção `-t`
-té usado para criar um arquivo com um timestamp de modificação e acesso atual.-t, adiciona um timestamp atual ao arquivo sem criar um novo.Pode-se fornecer uma string que consiste no ano, mês, dia, hora, minuto e segundo. Todos esses são números escritos juntos,excetoque um ponto separa o minuto e o segundo. Então, precisamos de uma maneira de extrair esses números e inserir o ponto.
É aí que entraa
ferramenta
de corteespecificada. Ela pode ser dada um conjunto de caracteres para selecionar, e eu especifiquei um conjunto diferente representando os apropriados, dependendo da categoria a que um nome de arquivo se encaixa. Para inserir o ponto, utilizei
Para substituir os dois últimos caracteres por um ponto seguido deles.
O primeiro script foi para testar se estava obtendo os resultados corretos.
Este aqui define os tempos de arquivo.
Para cada arquivo na pasta atual:
Opção "-c" para o comando "touch".
Este comando define o tempo de modificação e criação de um arquivo.
O comando "touch" é usado para atualizar os tempos de acesso, modificação e criação de arquivos.
"c" é uma opção para especificar o modo de atualização do tempo do arquivo.
Evita que ele crie um arquivo se um com esse nome já existir.
Para cada arquivo na pasta: se o nome do arquivo contiver "BURST", cria um novo arquivo com um timestamp. Se contiver "IMG_" ou "VID_", cria um arquivo com base na data e hora. Caso contrário, cria um arquivo com o nome formatado.
O script rodou sobre todos os arquivos em menos de 15 segundos e ajustou corretamente o horário de cada um. Tarefa concluída, certo? Bem, depois que fiz isso, percebi que havia espaço para melhorias. O script provavelmente seria mais rápido se eu usasse um `case` em vez de um `if`.uma abordagem mais eficiente
um `case`
a construção de um novo algoritmoum `if` mais simplesum `case` para cada condiçãoEstrutura chamadagrepvárias vezes. Embora a notação de correspondência de padrões usada comcasonão seja tão flexível e possa lidar com menos situações quanto a sintaxe de expressão regular disponível comgrep, neste caso (veja o que eu fiz ali?) é suficiente. Testando-o, usandocasoReduziu o tempo de execução em 45%.
Substituindo.
Se.
Com.
Caso.
— os comandos a serem executados para cada categoria de nome de arquivo podem permanecer exatamente os mesmos.
Para cada arquivo em *:
Não consegui completar completamente.AwkFora da minha mente, embora, e eu eventualmente cheguei com umAwkUm script para o mesmo propósito. Este éLongeMais rápido, provavelmente porque tudo pode ser feito dentroAwkExceto modificar realmente os tempos de arquivo, o que é possível usandoo
sistema()
funçãopara chamartocar. Consegui reduzir 90% do tempo de execução, o que, para 800 arquivos, não é um grande problema, mas pode fazer a diferença se você tiver centenas de milhares de arquivos.
O
awk
Os correspondentes de ambos os scripts acima. Diferente deles,
ls
é usado para alimentá-lo com a lista de nomes de arquivos. Temos todo o poder das expressões regulares estendidas disponíveis para usar na correspondência com os nomes de arquivos.
next
comando faz com que
awk
pule quaisquer pares de padrão-ação restantes e vá para a próxima linha de entrada.
ls | awk '/BURST/ { print $0, substr($0, 21, 12) "." substr($0, 33, 2) }; /^(IMG_|VID_)/ { print $0, substr($0, 5, 8) substr($0, 14, 4) "." substr($0, 18, 2) }; { print $0, substr($0, 1, 8) substr($0, 10, 4) "." substr($0, 14, 2) }'
Uma outra otimização que me ocorreu mais tarde foi não chamar o`system()`diretamentedo`awk`, mas sim tero `awk`imprimir um conjunto de linhas de comando. Estas podem então ser encadeadas paraPara ser realmente executado. Esta versão reduziu o tempo de execução em 95% em comparação com o meu script original.
A versão mais rápida que consegui criar. Se você executá-la sem o
| sh
Provavelmente, isso poderia ter sido feito com a mesma facilidade no Windows usando o PowerShell da Microsoft. Não estou muito familiarizado com ele, mas imagino (ou espero) que ele inclui comandos para gerenciar coisas básicas como manipulação de texto e modificação de tempos de arquivos. Se você estiver preso em um ambiente onde não tem um sistema semelhante ao UNIX disponível, investigue como realizar uma tarefa com as ferramentas que você tem.
Embora eu tivesse as informações necessárias nos nomes de arquivo para usar, isso pode não ser o caso em todas as situações. Você poderia procurar outras fontes de datas — a maioria das câmeras digitais adiciona tags EXIF a um arquivo JPEG, fornecendo a data e a hora em que foi criado. (Espero que o relógio da câmera esteja configurado corretamente.) Embora não haja uma utilidade UNIX padrão para ler essas tags, ferramentas de software livre e de código aberto estão amplamente disponíveis para esse propósito. Encontrei uma chamada `exiftags`.
É provavelmente verdade que isso poderia ter sido realizado com a mesma facilidade em Windows usando o PowerShell da Microsoft. Não estou muito familiarizado com ele, mas imagino (ou espero) que ele inclui comandos para gerenciar coisas básicas como manipulação de texto e modificação de tempos de arquivos. Se você estiver preso em um ambiente onde não tem um sistema semelhante ao UNIX disponível, investigue como realizar uma tarefa com as ferramentas que você tem.
Embora eu tivesse as informações necessárias nos nomes de arquivo para usar, isso pode não ser o caso em todas as situações. Você poderia procurar outras fontes de datas — a maioria das câmeras digitais adiciona tags EXIF a um arquivo JPEG, fornecendo a data e a hora em que foi criado. (Espero que o relógio da câmera esteja configurado corretamente.) Embora não haja uma utilidade UNIX padrão para ler essas tags, ferramentas de software livre e de código aberto estão amplamente disponíveis para esse propósito. Encontrei uma chamada `exiftags`.`exiftags`que incluiu a utilidadeexiftimeque especificamente gera dados EXIF relacionados ao tempo. O formato de saída foi um pouco mais difícil de lidar, masawkconseguiu gerenciá-lo com um pouco de incentivo.
Exemplo de saída gerada pelo
exiftime
. Observe que a primeira linha com o nome do arquivo éApenasImpresso se houver mais de um nome de arquivo fornecido como argumento. Além disso, para
sinal-divertido.jpg
Parece que editei essa foto depois de tirá-la e o software de edição atualizou a tag "Criada", mas deixou as outras intactas. Nem todas as imagens terão necessariamente tags de criação, geração e digitalização; apenas usaremos as que existem. Redirecionei o erro padrão para
/dev/null
para remover mensagens de erro para arquivos que não possuem tags EXIF; lidaremos com esses abaixo.
$ exiftime *.jpg 2>&1 /dev/null
Podemos aproveitar o fato de que diferentes registros são separados por uma linha em branco. Em
awk
quando
RS
é definido como uma string vazia e
FS
é definido como um caractere de nova linha, cada conjunto de linhas não vazias é tratado como um registro e cada linha dentro desses conjuntos é tratada como um campo. Uma ou mais linhas em branco separam cada registro. Para a saída de
exiftime
, isso significa que
$1
O arquivo conterá o nome do arquivo e...
$2
...a primeira linha após o nome do arquivo. Para arquivos sem a tag de data EXIF, ...
$2
Isso será uma string vazia, que é tratada por
...a data e hora extraídas do arquivo.
Contido em...
...o cabeçalho do arquivo.
O que se segue é o conteúdo...
$2
...do arquivo.
Sub
A chamada de função remove o dois-pontos que
Exiftime
Imprime após o nome do arquivo, e o
Gsub
A chamada de função remove todos os caracteres não numéricos da data e hora na tag. (Depois de uma vírgula dentro de uma
Print
Declaração, uma barra invertida não é necessária para continuar a linha.) Além disso, desta vez me preocupei em imprimir aspas ao redor do nome do arquivo, caso ele contenha espaços.
`exiftime *.jpg 2>/dev/null | awk 'BEGIN { FS = "\n"; RS = "" } { sub(":$", "", $1); gsub("[^0-9]", "", $2) } { print "touch -c -t", substr($2, 1, 12), ".", substr($2, 13, 2), "\"", $1, "\"" }` touch -c -t 202605081547.43 "20260508_154743.jpg" touch -c -t 202605081550.44 "20260508_155044.jpg" touch -c -t 201701242314.04 "amusing-sign.jpg" touch -c -t 201501010002.19 "dscf3011.jpg" `
Eu imaginaria que existe algum programa de gerenciamento de fotos lá fora que eu poderia ter usado para alcançar isso. Mas então eu teria que localizá-lo, verificar que não era algum lixo carregado de malware, baixá-lo e instalá-lo. E é provável que ele quisesse assumir todas as fotos no meu laptop. Em vez disso, usando ferramentas padrão do UNIX e capacidades de shell comoSe
, casoAtravés de substituições de processo e pipelines, consegui concluir a tarefa sem precisar instalar nada.
As técnicas que descrevi podem ser utilizadas em diferentes circunstâncias e com a saída de diferentes utilidades. Minha intenção não foi apenas explicar como resolver esse problema específico, mas espero que eu te ensine algumas coisas que você possa aplicar em muitas situações. Talvez, se você as usar para enfrentar um desafio seu, você registrará um episódio para o HPR para compartilhar o que sabe.
