Pertanyaan Ekstensi file yang benar


Saya memiliki sekitar 12.000 gambar dari jenis file yang berbeda tetapi masing-masing dari mereka berganti nama menjadi * .jpg.

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


14
2018-06-03 18:31


asal


secara rekursif, atau dalam direktori "datar"? - Jacob Vlijm
Pertanyaan serupa Bagaimana saya dapat mengganti nama file / mengubah ekstensi mereka berdasarkan mimetype dengan skrip? dan Batch rename - beberapa jenis gambar - steeldriver
@steeldriver cukup dekat, tetapi file-file itu tidak tidak memiliki ekstensi, di sini mereka punya salah perpanjangan. - Jacob Vlijm
@ JakobVlijm 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:


Anda dapat melakukannya dengan 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 @ A.B tetapi menggunakan glob shell sebagai gantinya find. Itu ${f%%.*} adalah nama file tanpa ekstensi. Itu -0 dari file perintah membuatnya mencetak \0 setelah nama file yang kemudian kita gunakan grep jenis file. Ini harus bekerja dengan nama file yang sewenang-wenang, termasuk yang mengandung spasi, baris baru atau apa pun. Itu ${type,,} adalah trik untuk mendapatkan ekstensi huruf kecil. Itu akan berubah PNG untuk png.

Anda tidak mengatakan dalam pertanyaan Anda, tetapi jika Anda perlu ini menjadi rekursif dan turun ke subdirektori, Anda dapat 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

Itu shopt -s globstar akan mengaktifkan opsi globstar bash yang memungkinkan ** mencocokkan subdirektori:

globstar

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


21
2018-06-03 20:39



@ A.B. lihat pembaruan. Ini memungkinkan ** untuk recurse ke subdirektori. - terdon♦
@ A.B. d'oh! Terima kasih, sudah diperbaiki. - terdon♦
Titik koma di ujung 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♦
@Campa tidak, tentu saja tidak. Ini juga akan menambahkan ekstensi palsu ke file biner, file teks normal, skrip perl dan python, dan daftar berjalan. Pertanyaan itu bertanya tentang gambar khusus dan mereka cenderung memiliki nama yang sama dengan ekstensi biasa mereka. Ingat bahwa ekstensi di Linux adalah opsional, dengan sangat sedikit pengecualian, mereka sebenarnya tidak melakukan apa-apa. Mereka membantu pengguna mengatur data mereka, OS tidak peduli dengan mereka. - terdon♦


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

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

Seperti itu, secara khusus mengganti nama file dengan ekstensi .jpg, seperti yang disebutkan dalam pertanyaan. Dengan sedikit perubahan, itu bisa cocok untuk mengubah nama ekstensi apa pun, atau kumpulan ekstensi tertentu, ke yang benar (atau tanpa ekstensi, seperti 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)

Bagaimana cara menggunakan

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

    python3 /path/to/rename.py <directory>
    

10
2018-06-03 19:34



+1 untuk sederhana dan mudah dibaca, tidak seperti solusi berbasis bash. - Davide


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


Anda dapat menggunakan perintah file untuk 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 diganti 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

2
2018-06-03 19:06



Perhatikan bahwa ini akan pecah dalam kasus yang tidak mungkin bahwa salah satu nama file mengandung baris baru. - terdon♦
@terdon Ya, saya sudah berpikir. Sayangnya saya tidak tahu apa yang bisa saya lakukan. Bisakah kamu menolong? - A.B.
Saya tidak tahu bagaimana melakukan ini dengan benar menggunakan awk. Ini bukan alat yang tepat untuk pekerjaan itu. Entah digunakan find -exec bash -c "..." dan lakukan semuanya di sana atau gunakan while read -d '' name type untuk membagi nama file dan file output dan kemudian parse $type untuk mendapatkan jenis file. Tidak layak benar-benar, lihat jawaban saya untuk cara melakukannya dengan lebih mudah dalam bash yang murni (ish). - terdon♦