Bash

Bash - 檔案名稱到文件名,不正確的匹配(zip,cdg,mp3)

  • December 8, 2020

我編寫了一個腳本,用於檢查 zip 存檔中的兩個特定副檔名。進行了幾項檢查以確定存檔是否只有 2 個文件,然後處理它們。如果存檔少於 2 個,它將把存檔移動到“BAD”文件夾。如果存檔超過 2 個,它將把存檔移動到“FIX”目錄。

處理步驟是提取文件,並將它們重命名為與 zip 存檔相同的名稱。

當條件完美時,這一切都很好。但是當它們不完美時……它會變得醜陋。

我遇到了一種情況,即使文件可能有正確的 2 個文件和副檔名,但如果文件有特殊字元(如 Ø、反引號、逗號、撇號等)……它們會被處理(我假設)像正則表達式語法或表達式。

這是程式碼:

#! /bin/bash

prefix="0000_"

mkdir -p ${prefix}{DONE,FIX,BAD}

shopt -s nocaseglob
for i in *.ZIP;
   do
       zip_name="$i"
       pair_exists=$(unzip -Z1 "$i" | grep -E -- '.cdg|.CDG|.mp3|.MP3' | wc -l)
       log="${prefix}LOG.txt"

       if [ $pair_exists -eq 2 ]
           then
               cdg_name=$(unzip -Z1 "$i" | grep -E -- '.cdg|.CDG' | awk '{print substr($0,index($0,$1))}')
               mp3_name=$(unzip -Z1 "$i" | grep -E -- '.mp3|.MP3' | awk '{print substr($0,index($0,$1))}')
               new_cdg_name="$(echo "${zip_name%.*}.cdg")"
               new_mp3_name="$(echo "${zip_name%.*}.mp3")"
               7za x "$i" -aoa -y -ba >> ./$log
               mv ./"$cdg_name" ./"$new_cdg_name"
               mv ./"$mp3_name" ./"$new_mp3_name"
               mv ./"$zip_name" ./${prefix}DONE/

       elif [ $pair_exists -gt 2 ]
           then
               echo ""
               echo "NEEDS FIXED: $zip_name"
               mv ./"$zip_name" ./${prefix}FIX/

       elif [ $pair_exists -lt 2 ]
           then
               echo ""
               echo "ARCHIVE IS BAD: $zip_name"
               mv ./"$zip_name" ./${prefix}BAD/

       else
               echo ""
               echo "MUST BE BROKE!"
               echo ""
       fi
   done
exit

一切都很酷,直到我得到 mv 語句。

               mv ./"$cdg_name" ./"$new_cdg_name"
               mv ./"$mp3_name" ./"$new_mp3_name"

我覺得也許 mv 可能不是在這裡使用的正確方法,但我也遇到了重命名的嚴重問題。我想更多,所以我需要一些程式碼來告訴命令不要將變數中的任何字元視為要執行的操作。

這是我所看到的……

----- 範例 1 -----

壓縮文件名:

CB30035-05 - 簡單計劃 - 我願意做任何事.zip

ZIP 內的文件:

CB30035-05 - 簡單計劃 - 我願意做任何事.cdg
CB30035-05 - 簡單的計劃 - 我願意做任何事.mp3

錯誤:

mv: cannot stat './CB30035-05 - Simple PlanI\'d Do Anything.cdg': 沒有這樣的文件或目錄
mv: cannot stat './CB30035-05 - Simple PlanI\'d Do Anything.mp3': 沒有這樣的文件或目錄

----- 範例 2 -----

壓縮文件名:

CBSE5-0068 - 木匠,我們知道.zip

ZIP 內的文件:

cbscdge450-5-0068 - 木匠 - 我們所知道的.cdg
cbscdge450-5-0068 - 木匠 - 我們所知道的.mp3

錯誤:
mv: cannot stat './cbscdge450-5-0068 - Carpenters - For All We Know.cdg\ncbscdge450-5-0068 - Carpenters - For All We Know.mp3': 沒有這樣的文件或目錄

我已經搜尋了一個類似的問題,但是我發現的主題並不真正適合我的問題,或者有些程式碼讓我有點想不通,試圖弄清楚如何將其合併到我的腳本中。

我將不勝感激任何幫助。謝謝!

(注意:我知道上面腳本中的“awk”沒有做任何事情。我移至“unzip -Z1”,這似乎解決了我之前從 zip 文件中獲取文件名的努力。我已經離開了將其放入並對其進行調整,以防萬一我需要它。)

編輯2020120601:


作為對@Wieland 的回應,我從 zip 文件名中刪除了雙空格。但是在裡面的文件上留下了雙倍的空格。我將無法修復每個文件的內部,因為有很多文件,所以我需要弄清楚如何按原樣修復它們。刪除 zip 文件上的雙空格並沒有改變我的結果。

作為對@steeldriver 的回應,這裡有更多資訊。下面是我嘗試使用的每個命令的返回值(注意 7za ……它沒有生成文件名的方法,所以我之前使用的是 awk)。

我還更改了要閱讀的程式碼\.cdg$|\.CDG$|\.mp3$|\.MP3$,這並沒有改變我的結果,但我同意涵蓋該基礎。

zipinfo -1 "CB30035-05 - 簡單計劃 - 我願意做任何事.zip"

CB30035-05 - 簡單的計劃我會做任何事.cdg
CB30035-05 - 簡單的計劃我會做任何事.mp3

unzip -Z1 "CB30035-05 - 簡單計劃 - 我願意做任何事.zip"

CB30035-05 - 簡單的計劃我會做任何事.cdg
CB30035-05 - 簡單的計劃我會做任何事.mp3

7za -ba l "CB30035-05 - 簡單計劃 - 我願意做任何事.zip" 

2003-06-27 14:41:56 ....A 1516512 379652 CB30035-05 - 簡單的計劃我會做任何事.cdg
2003-06-27 14:42:22 ....A 3369876 3112004 CB30035-05 - 簡單的計劃我會做任何事.mp3

編輯 2020120701:


@G-Man 說“恢復莫妮卡”

感謝您在您的解釋中包含如此多的細節。我很感激。我會將您建議的模組整合到腳本中。關於

如果您“將程式碼更改為讀取 .cdg $ |.CDG $ |.mp3 $ |.MP3 $ 這並沒有改變我的結果”,那麼你做錯了……

我很確定我密切關注你的例子。我曾評論說我這樣做了,但反斜杠已從我的評論中刪除。我也已經實現了 grep “c”。但顯然嚴重錯過了“i”選項。那肯定會清理乾淨。

這是現在的程式碼……

#! /bin/bash

prefix="00001_"

mkdir -p ${prefix}{DONE,FIX,BAD}

shopt -s nocaseglob
for i in *.ZIP;
   do
       zip_name="$i"
       pair_exists=$(unzip -Z1 "$i" | grep -Eci -- '\.cdg$|\.mp3$')

       if [ $pair_exists -eq 2 ]
           then
               cdg_name=$(unzip -Z1 "$i" | grep -E -- '\.cdg$|\.CDG$')
               mp3_name=$(unzip -Z1 "$i" | grep -E -- '\.mp3$|\.MP3$')

               base_name="${zip_name%.*}"
               new_cdg_name="$base_name.cdg"
               new_mp3_name="$base_name.mp3"

                       printf 'cdg_name = [%s]\n' "$cdg_name"
                       printf 'mp3_name = [%s]\n' "$mp3_name"

               unzip -qq "$i"
               mv -- "${cdg_name}" "${new_cdg_name}"
               mv -- "${mp3_name}" "${new_mp3_name}"
               mv ./"$zip_name" ./${prefix}DONE/

       elif [ $pair_exists -gt 2 ]
           then
               echo ""
               echo "NEEDS FIXED: $zip_name"
               mv ./"$zip_name" ./${prefix}FIX/

       elif [ $pair_exists -lt 2 ]
           then
               echo ""
               echo "ARCHIVE IS BAD: $zip_name"
               mv ./"$zip_name" ./${prefix}BAD/

       else
               echo ""
               echo "HMM"
               echo ""
       fi
   done
exit

我也納入了您的更改。

關於調試,我再次使用了“echo”。這就是我的測試腳本中的內容……

echo ""
echo "-----"
echo   $pair_exists
echo   $zip_name
echo   $cdg_name
echo   $mp3_name
echo   $new_cdg_name
echo   $new_mp3_name
echo   $prefix
echo   $log
echo "-----"
echo ""

它產生與您的“printf”相同的東西。不過我很喜歡你花哨的方式,並且會採用你的風格。:)

回答第 5 點。我從使用 7z.exe 中得到了這個想法。實際上是通過 GUI 來查看的。現在我將發布我的 Windows 機器所看到的螢幕截圖,然後我將再次發布我的 linux 機器產生的內容。

視窗

在此處輸入圖像描述

LINUX

在此處輸入圖像描述

我不知道為什麼會這樣。在看了一會兒之後,我的一部分認為也許……我不知何故搞砸了我的環境。我以前沒有遇到過這樣的問題,這讓我把頭髮拉了出來!

現在! 給了你所有這些資訊,也許我還沒有給你足夠的資訊。但我需要告訴你。對程式碼進行更改後,它會產生正確的結果!即使我的系統仍然從文件名中去掉“ - ”,它會產生所需的最終結果。我希望這些文件採用 zip 文件的名稱,這就是它現在正在做的事情。

在此處輸入圖像描述

我所做的改變…

  1. 清理pair_exists

unzip -Z1 "$i" | grep -Eci -- '\.cdg$|\.mp3$' 2. 清理 cdg 和 mp3_name 提取並刪除 awk

cdg_name=$(unzip -Z1 "$i" | grep -E -- '\.cdg$|\.CDG$')

mp3_name=$(unzip -Z1 "$i" | grep -E -- '\.mp3$|\.MP3$') 3. 合併了新的 base_name 建議並刪除了 echo

base_name="${zip_name%.*}"

new_cdg_name="$base_name.cdg"

new_mp3_name="$base_name.mp3" 4. 添加了“printf”調試行(在執行 150k+ 文件時將它們註釋掉)

printf 'cdg_name = [%s]\n' "$cdg_name"

printf 'mp3_name = [%s]\n' "$mp3_name" 5. 我將解壓縮器更改為解壓縮以與工具集保持一致

unzip -qq "$i"

我不知道修復發生在哪裡,但我非常感謝您的幫助@G-Man 說“恢復莫妮卡”並幫助我解決這個問題並提供一些非常可靠的建議。

謝謝!

  1. Steeldriver 的評論幾乎可以肯定地確定了問題的一部分。如果您“更改了要閱讀的程式碼\.cdg$|\.CDG$|\.mp3$|\.MP3$ ,但這並沒有改變我的結果”,那麼您做錯了——具體來說,您做的不完整。部分問題在於命令
cdg_name=$(unzip -Z1 "$i" | grep -E -- '.cdg|.CDG' | awk '{print substr($0,index($0,$1))}')

必須更改為

cdg_name=$(unzip -Z1 "$i" | grep -E -- '\.cdg$|\.CDG$' | awk '{print substr($0,index($0,$1))}')

因為 匹配,所以設置為兩個名稱*的串聯**,由換行符分隔。*從錯誤消息中  可以清楚地看出這一點。cb**s*cdg***e450-5-0068 - Carpenters …``.cdg``cdg_name``mv 2. 僅出於簡化目的,您可以更改

unzip -Z1 "$i" | grep -E -- '\.cdg$|\.CDG$|\.mp3$|\.MP3$' | wc -l

unzip -Z1 "$i" | grep -Ec -- '\.cdg$|\.CDG$|\.mp3$|\.MP3$'

**(**使用 的count 選項grep)甚至

unzip -Z1 "$i" | grep -Eci -- '\.cdg$|\.mp3$'

(使用i gnore case 選項grep)。 3. 幾乎沒有任何理由說。事實上,我傾向於說沒有理由這樣做,但有人可能會發現一個奇怪的極端案例,它是有益的。具體來說,$(echo "*something*")

new_cdg_name="$(echo "${zip_name%.*}.cdg")"
new_mp3_name="$(echo "${zip_name%.*}.mp3")"

可以改為

new_cdg_name="${zip_name%.*}.cdg"
new_mp3_name="${zip_name%.*}.mp3"

我什至可以將它們更改為

base_name="${zip_name%.*}"
new_cdg_name="$base_name.cdg"
new_mp3_name="$base_name.mp3"

PS 嚴格來說,上面的引號不是必需的,但是除非你有充分的理由不這樣做,否則一直使用它們是一種很好的做法。

PPS 在錯誤的上下文中, 可能會執行更改為 (即,將多個空格壓縮為一個)之類的操作。$(echo "*something*")``Plan  - I``Plan - I 4. 冒著政治不正確的風險,想像一下你是試圖破案的警察,你所能做的就是拿著雙筒望遠鏡坐在罪犯總部外。如果你能得到竊聽器或線人,這樣你就可以知道大樓裡發生了什麼,那不是更好嗎?調試就像試圖解決犯罪一樣——雖然外部資訊(即和的輸出zipinfo7za單獨執行)對於理解問題很重要,但它確實有助於獲取內部資訊。因此,作為例行調試步驟,我建議添加如下語句

printf 'cdg_name = [%s]\n' "$cdg_name"
printf 'mp3_name = [%s]\n' "$mp3_name"

到腳本。這將很明顯設置為兩個名稱的串聯,它可能會cdg_name幫助您跟踪.I'd Do Anything``I\'d Do Anything 5. 嚴格來說,這應該是一個註釋,但是,只要我在這裡:你從哪裡知道其中的成員文件的名稱CB30035-05 - SIMPLE PLAN - I'D DO ANYTHING.zip

  • CB30035-05 - Simple Plan - I'd Do Anything.cdg
  • CB30035-05 - Simple Plan - I'd Do Anything.mp3當您沒有向我們展示任何Plan顯示 the和 I? 之間 任何內容的命令時
  1. 正如我上面提到的,這I\'d Do Anything是一個難題。但是,您是否真的有任何與逗號、反引號或非 ASCII 字元(如“é”、“Φ”、“Ø”、“θ”、“½”或“∞”)相關的問題範例?

引用自:https://unix.stackexchange.com/questions/623227