Ekstensi file yang benar

15

Saya memiliki sekitar 12000 gambar dari jenis file yang berbeda tetapi masing-masing dari mereka diganti namanya * .jpg.

Sekarang saya ingin memberi mereka ekstensi yang tepat kembali, bagaimana saya bisa melakukannya

akxer
sumber
2
secara rekursif, atau dalam direktori "flat"?
Jacob Vlijm
1
@steeldriver cukup dekat, tetapi file-file itu tidak memiliki ekstensi, di sini mereka memiliki ekstensi yang salah .
Jacob Vlijm
1
@ JacobVlijm itu sebabnya saya tidak menandai pertanyaan sebagai duplikat: namun metode yang diusulkan dalam jawaban memiliki nilai di sini, IMHO
steeldriver
@steeldriver Saya sepenuhnya setuju.
Jacob Vlijm

Jawaban:

22

Anda dapat melakukannya dengan relatif mudah di bash:

for f in *jpg; do 
    type=$(file -0 -F" " "$f" | grep -aPo '\0\s*\K\S+') 
    mv "$f" "${f%%.*}.${type,,}"  
done

Ini adalah ide yang sama dengan jawaban @ AB tetapi menggunakan shell shell sebagai gantinya find. Ini ${f%%.*}adalah nama file tanpa ekstensi. The -0dari fileperintah membuatnya mencetak \0setelah nama file yang kemudian kita gunakan untuk grepjenis file. Ini harus bekerja dengan nama file yang sewenang-wenang, termasuk yang berisi spasi, baris baru atau apa pun. Ini ${type,,}adalah trik untuk mendapatkan ekstensi huruf kecil. Itu akan dikonversi PNGmenjadi png.

Anda tidak mengatakan dalam pertanyaan Anda, tetapi jika Anda ingin ini bersifat rekursif dan turun ke subdirektori, Anda bisa menggunakan ini sebagai gantinya:

shopt -s globstar
for f in **/*jpg; do 
    type=$(file -0 -F" " "$f" | grep -aPo '\0\s*\K\S+') 
    mv "$f" "${f%%.*}.${type,,}"  
done

Opsi ini shopt -s globstarakan mengaktifkan bash's globstar yang memungkinkan **mencocokkan subdirektori:

globstar

Jika diatur, pola ** yang digunakan dalam konteks ekspansi pathname akan cocok dengan semua file dan nol atau lebih direktori dan subdirektori. Jika pola diikuti oleh a, hanya direktori dan subdirektori yang cocok.

terdon
sumber
@ AB lihat pembaruan. Hal ini memungkinkan **untuk muncul kembali ke dalam subdirektori.
terdon
Titik koma di akhir setiap baris itu berlebihan, bukan?
Paddy Landau
@ PaddyLandau ya, saya mengujinya sebagai satu liner dan menambahkan baris baru untuk kejelasan di sini. Saya lupa menghapusnya. Perhatikan bahwa mereka tidak salah, hanya berlebihan seperti yang Anda katakan.
terdon
Hebat, meskipun filetidak selalu menentukan ekstensi itu tampaknya: itu mengubah file bash ke foo.bourne-againsini misalnya!
Campa
1
@ Campa tidak, tentu saja tidak. Itu juga akan menambahkan ekstensi palsu ke file biner, file teks normal, skrip perl dan python dan daftar berjalan. Pertanyaannya adalah bertanya tentang gambar secara khusus dan mereka cenderung memiliki nama yang sama dengan ekstensi mereka yang biasa. Ingatlah bahwa ekstensi di Linux adalah opsional, dengan sedikit pengecualian, mereka sebenarnya tidak melakukan apa-apa. Mereka membantu pengguna mengatur data mereka, OS tidak peduli tentang mereka.
terdon
11

Script di bawah ini dapat digunakan untuk (secara rekursif) mengganti nama ekstensi yang salah diatur .jpg,, ke yang benar. Jika menemukan file yang tidak dapat dibaca, itu akan melaporkannya dalam output skrip.

Script menggunakan imghdrmodul, untuk mengenali jenis berikut: rgb, gif, pbm, pgm, ppm, tiff, rast, xbm, jpeg, bmp, png. Lebih lanjut tentang imghdrmodul di sini . Daftar dapat diperpanjang dengan lebih banyak jenis, seperti yang disebutkan dalam tautan.

Seperti itu, ia secara khusus mengganti nama file dengan ekstensi .jpg, sebagaimana disebutkan dalam pertanyaan. Dengan perubahan kecil, bisa cocok untuk mengubah nama ekstensi apa pun, atau serangkaian ekstensi tertentu, menjadi yang benar (atau tanpa ekstensi, seperti di sini ).

Naskah:

#!/usr/bin/env python3
import os
import imghdr
import shutil
import sys

directory = sys.argv[1]

for root, dirs, files in os.walk(directory):
    for name in files:
        file = root+"/"+name
        # find files with the (incorrect) extension to rename
        if name.endswith(".jpg"):
            # find the correct extension
            ftype = imghdr.what(file)
            # rename the file
            if ftype != None:
                shutil.move(file, file.replace("jpg",ftype))
            # in case it can't be determined, mention it in the output
            else:
                print("could not determine: "+file)

Cara Penggunaan

  1. Salin skrip ke file kosong, simpan sebagai rename.py
  2. Jalankan dengan perintah:

    python3 /path/to/rename.py <directory>
    
Yakub Vlijm
sumber
+1 untuk sederhana dan mudah dibaca, tidak seperti solusi berbasis bash.
Davide
3

Catatan: Pendekatan saya tampaknya terlalu rumit. Saya lebih suka jawaban terdon di tempat Anda.


Anda dapat menggunakan perintah fileuntuk menentukan jenis file:

% file 20050101_14-24-37_330.jpg 
20050101_14-24-37_330.jpg: JPEG image data, EXIF standard 2.2, baseline, precision 8, 1200x1600, frames 3

% file test.jpg
test.jpg: PNG image data, 1192 x 774, 8-bit/color RGBA, non-interlaced

Dengan informasi ini, file dapat diubah namanya:

Silakan lakukan tes sebelum Anda menerapkan perintah ke gambar Anda

find . -type f -iname "*.jpg" -print0 | xargs -0 -I{} file -F"<separator>" {} | 
 awk -F " image data" '{print $1}' | 
  awk -F"<separator> " '{
   system("mv \""$1"\" $(dirname \""$1"\")/$(basename -s .jpg \"" $1 "\")."$2)
   }'

Contoh

% find . -type f -name "*.jpg"
./test.jpg
./sub/20050101_14-24-37_330.jpg

% find . -type f -iname "*.jpg" -print0 | xargs -0 -I{} file -F"<separator>" {} | awk -F " image data" '{print $1}' | awk -F"<separator> " '{system ("mv \""$1"\" $(dirname \""$1"\")/$(basename -s .jpg \"" $1 "\")."$2)}'

% find . -type f -iname "*"    
./test.PNG
./sub/20050101_14-24-37_330.JPEG
AB
sumber
Perhatikan bahwa ini akan pecah jika tidak ada nama file yang berisi baris baru.
terdon
@terdon Ya, saya sudah berpikir. Sayangnya saya tidak tahu apa yang bisa saya lakukan. Bisakah kamu menolong?
AB
Saya tidak tahu bagaimana melakukan ini dengan benar menggunakan awk. Itu bukan alat yang tepat untuk pekerjaan itu. Baik gunakan find -exec bash -c "..."dan lakukan segala sesuatu di sana atau gunakan while read -d '' name typeuntuk membagi nama file dan fileoutput dan kemudian parsing $typeuntuk mendapatkan tipe file. Tidak sepadan, lihat jawaban saya untuk melakukannya dengan lebih mudah di bash (ish) murni.
terdon