我今天在午休期間編寫了一個 bash 腳本,該腳本在目錄中找到無擴展名檔案並向這些檔案附加檔案副檔名。
該腳本相對較長,因為我添加了一堆標誌和目錄選擇以及是否複製或覆蓋文件等內容,但可以簡單地複製其功能的主要部分:
#recursively find files in current directory that have no extension
for i in $(find . -type f ! -name "*.*"); do
#guess that extension using file
extfile=$(file --extension --brief $i)
#select the first extension in the event file spits something weird (e.g. jpeg/jpe/jfif)
extawk=$(echo $extfile | awk -F/ '{print $1}')
#copy the file to a file appended with the extension guessed from the former commands
cp -av $i $i.$extawk
done
在我的實際腳本中,它有點整潔——我只是想在這裡分割命令,這樣我就可以評論我這樣做的原因。
我的問題:find
結合使用file
使用可能不是最簡單的方法——什麼是最好的如何在多個目錄中遞歸猜測和附加大量不同檔案類型的副檔名?
答案1
for x in $(find …)
失敗了包含空格(常見)或通配符(較不常見)的檔名。永遠不要解析find
.使用-exec
。
讓我們建立一個 zmv 命令來執行您想要的操作。首先,讓我們建立搜尋模式:
autoload zmv
zmv -C -o -a -n -Q '(*/)#^*.*(.)' …
-C
導致文件被複製而不是移動。-o -a
傳遞-a
到cp
.-n
意味著不採取行動,只列印將要做什麼。一旦你感到高興就將其刪除。-v
如果您想執行操作但也想列印正在執行的操作,請將其替換為。-Q
使全域限定符在模式中。(*/)#
符合零個或多個目錄。它使用#
全域運算符(extended_glob
在 zmv 中始終啟用)。^*.*
使用^
glob 運算子來匹配.
名稱中不含 a 的檔案。(.)
是一個 glob 限定符,它將匹配限制為常規檔案。…
將被替換文字替換。這可以用來$f
指原始名稱。
zmv
在執行任何替換之前計算所有替換名稱,如果任何替換名稱已存在或有衝突,則會抱怨。替換名稱與原始名稱相同的檔案將被跳過。
現在讓我們建立替換文字。我們會用到很多參數擴充特徵。
- 請求
file
延期:$(file --extension --brief -- $f)
- 前置一個
.
, 準備替換:($(echo -n .; file --extension --brief -- $f)
這也可以透過參數擴展來完成:${:-.$(…)}
。) - 如果有多個建議的副檔名(以斜線分隔),則僅保留第一個:
${$(echo -n .; file --extension --brief -- $f)%%/*}
- 如果建議的擴展名為空 或
???
,則放棄(將.
或替換.???
為空字串):${${$(echo -n .; file --extension --brief -- $f)%%/*}:#.(|\?\?\?)}
- 將新增的副檔名附加到
$f
(原始名稱)。如果我們附加的內容為空,則該文件將保持不變。
結果命令:
zmv -C -o -a -n -Q '(*/)#^*.*(.)' '$f${${$(echo -n .; file --extension --brief -- $f)%%/*}:#.(|\?\?\?)}'
這有點神秘,您可能更願意將生成替換的程式碼放在函數中並使用zmv … '$(add_extension $f)'
.
答案2
我認為最有效的方法是將文件的 mime 類型與位於 的資料庫進行比較/usr/share/mime/globs
。
- 球體在Linux中是檔案副檔名。給出的範例,輸出來自全域文件
application/x-mswinurl:*.url
text/x-mrml:*.mrl
text/x-erlang:*.erl
audio/x-pn-audibleaudio:*.aa
application/x-bzip-compressed-tar:*.tbz2
application/x-netshow-channel:*.nsc
application/x-hdf:*.h4
application/pgp-keys:*.key
text/x-idl:*.idl
text/x-chdr:*.h
application/vnd.ms-powerpoint.presentation.macroEnabled.12:*.pptm
application/vnd.ms-powerpoint.presentation.macroEnabled.12:*.pptm
application/vnd.visio:*.vsd
application/x-hdf:*.h5
video/vnd.mpegurl:*.m4u
- 在描述了類型範例 --> 後
text/x-erlang
,它告訴 Linux 將所有檔案識別*.
為埃爾蘭帶有擴展名.erl
[glob],這就是為什麼 -->*.erl
- 您可以新增自己的副檔名以計入
/etc/magic
檔案中
所以運行命令:
mimetype -bM file
b
論證只是告訴你type-app/extension
(短)M
論證手段魔法Linux 以字節碼、十六進位、二進位檢查檔案的方式,以驗證檔案是否確實如其所聲稱的那樣。模仿型不返回
/jpg/png/webp
只返回一種類型,並且它比file --mime-type file
返回:
image/webp
最後的想法
mimetype
最適合與二進位檔案例如 PDF、圖像、影片。這是因為它可以檢查二進位文件,相反,text plain
就是這樣,你需要識別一些東西,這更複雜,這就是為什麼文字編輯器可以識別不同的程式語言,它需要使用者和伺服器語言的幫助每種程式語言。
對於遞迴,我認為樹很好:
tree -FIi '*.*' | grep -v /$
- 參數
F
是將/
[slash] 新增到目錄,例如folder
→folder/
- 參數
I
是選擇模式的相反*.*
[這意味著選擇所有具有擴展名的檔案],所以相反的不是擴展名 - 參數
i
是從樹輸出中刪除空格 grep -v
是選擇反向,這就是為什麼你添加 -F/
參數樹命令位於開頭,因此您可以刪除目錄並僅獲取文件,擴展名為/$
.
在這裡查看更多信息默劇類型