Estou tentando acrescentar DateTimeOriginal da foto aos nomes dos arquivos, mas o script não consegue renomear?
linuxmint@linuxmint:~/Documents$ ./rename_prepend_date.sh /media/linuxmint/USB\ STICK/Old\ drive/My\ pictures/IMG_0569.JPG
mv: cannot move '/media/linuxmint/USB STICK/Old drive/My pictures/IMG_0569.JPG' to '20110424_/media/linuxmint/USB STICK/Old drive/My pictures/IMG_0569.JPG': No such file or directory
Renamed '/media/linuxmint/USB STICK/Old drive/My pictures/IMG_0569.JPG' to '20110424_/media/linuxmint/USB STICK/Old drive/My pictures/IMG_0569.JPG'
Aqui está meu script bash:
#!/bin/bash
# Check if exiftool is installed
if ! command -v exiftool &> /dev/null; then
echo "exiftool is not installed. Please install it first."
exit 1
fi
# Check if a file is provided as an argument
if [ $# -eq 0 ]; then
echo "Usage: $0 <filename>"
exit 1
fi
# Loop through each provided file
for file in "$@"; do
# Get the date from the metadata (DateTimeOriginal)
date=$(exiftool -d "%Y%m%d" -DateTimeOriginal "$file" | awk -F': ' '{print $2}')
# Check if the date was successfully extracted
if [ -z "$date" ]; then
echo "Could not find a date for file $file. Skipping..."
continue
fi
# Extract the file extension and base name
extension="${file##*.}"
base="${file%.*}"
# Create the new filename by prepending the date
new_file="${date}_${base}.${extension}"
# Rename the file
mv "$file" "$new_file"
echo "Renamed '$file' to '$new_file'"
done
Seu problema é que você está acrescentando o timestamp ao caminho completo em vez de apenas ao nome base. Mas você está dificultando sua vida por nada, já que
exiftool
suporta renomear arquivos com base em tags encontradas no próprio arquivo:Também é mais seguro, pois não renomeará se as tags não puderem ser extraídas ou se o arquivo de destino já existir.
A propósito, você não precisa
awk
se escrever:Ou:
Ou:
(
-s3
ou-s -s -s
, short short short para também pular a impressão dos nomes das tags).Algumas outras notas:
&> /dev/null
é a única coisa que é específica do bash no seu script. Se você substituí-lo por> /dev/null 2>&1
, seu script se tornash
sintaxe padrão, e você pode alterar o shebang para#! /bin/sh -
e remover a dependência do bash. Se eu fosse usar um shell diferente dosh
, eu preferiria usarzsh
do quebash
aqui, pois ele tem suporte integrado para extrair dirname (head) / basename (tail) / rootname / extension ($file:h
/$file:t
/$file:r
/$file:e
) e até mesmo uma ferramenta (zmv
) para renomear arquivos em lote com segurança.Você deve usar
--
(-
também funciona para os utilitáriossh
,zsh
oubash
no shebang e é mais idiomático lá ) para separar opções de não opções quando não puder garantir que as não opções não começarão com-
(exiftool ... -- "$file"
,mv -- "$file" "$new_file"
...)echo
geralmente não pode ser usado para dados arbitrários. Useprintf
em vez disso .erros devem ir para stderr. Alguns auxiliares de função comuns:
Então você pode fazer:
Mesmo mensagens informativas , qualquer coisa que não seja considerada a saída produzida pelo script (e que alguém possa querer usar, provavelmente nenhuma no seu caso) geralmente é enviada preferencialmente para stderr, pois é destinada ao usuário interativo, não para pós-processamento.
base="${file%.*}"
remove a parte depois da última.
no caminho completo . Então em umdir.d/image
, isso lhe dádir
(e.d/image
paraextension="${file##*.}"
). Aqui você não precisa extrair a extensão, pois não está fazendo nada útil com ela, mas no caso geral, você quer ter certeza de fazer isso apenas no último componente do caminho (o nome base )."$@"
é o quefor
os loops fazem por padrão, usandofor file do
é mais idiomático (e mais portátil) do quefor file in "$@"; do
.