僅將檔案名稱的部分內容轉換為大寫

僅將檔案名稱的部分內容轉換為大寫

在 shell 腳本程式中,如果轉換後的檔案名稱尚不存在,我需要將檔案名稱轉換為大寫。在這種特殊情況下,我只需將基本名稱更改為大寫,保留擴展名(如果有)不變。

我解決這個問題的想法是首先分別提取基本名稱和擴展名,使用 tr命令將基本名稱轉換為大寫,然後檢查目錄中是否存在更改的基本名稱和擴展名。

如果它不存在,那麼我將使用 mv 將原始檔案名稱更改為大寫基本名稱。現在我認為這可以透過兩種方式完成:首先使用expr,其次是使用cutwith .(space-period-space) 作為分隔符號。

如果我想用於expr提取基本名稱(例如從文件名 -python1.pyphonelist),那麼我寫了這個:

basefile=`expr "$filename" : '\(.*\)\.*.*' ` 

我也使用了\.*那些沒有任何副檔名的檔名,因為\.* 會忽略零次或多次出現的.,但這個表達式expr無法正常運作。對於任何文件名,它都會按原樣返回整個文件名。

誰能解釋一下我哪裡錯了。另請建議我如何使用expr僅從文件名中提取擴展名。

答案1

如果 shell 是bash,則僅使用 bash 參數擴充:

file="aaa.bbb.dat"

name=${file%.*} # delete everything after last dot 
ext=${file##*.} # delete everything up to last dot
upcase=${name^^*}.$ext # uppercase everything

echo "$upcase"
AAA.BBB.dat

嘗試更困難的情況:

file="déjà vu . dat "
name=${file%.*} # delete everything after last dot 
ext=${file##*.} # delete everything up to last dot
upcase=${name^^*}.$ext # uppercase everything
echo ":$upcase:"

給出:

:DÉJÀ VU . dat :

所以:

  • 在使用結果之前不需要雙引號
  • 即使對於非 ASCII 字符,大寫似乎也可以

答案2

當群組延伸多遠存在模糊性時,正規表示式引擎首先優先考慮最長的匹配。對於任何檔案名,\(.*\)匹配全名並\.*.*匹配空字串。

您將需要兩種情況:有或沒有擴展名。另請注意,如果檔案名稱以 開頭.,則這不是副檔名的開頭。

我不明白你為什麼要使用expr. Shell 參數操作更容易。

在轉換為大寫時,請注意trLinux 上的實作不支援非 ASCII 語言環境。它只進行位元組操作。例如echo accentué | tr a-z A-Z結果為ACCENTUé, not ACCENTUÉ。請改用 awk 等區域設定感知工具。在 bash 中,您可以使用${filename^^?},但在 sh 中不可用。確保您的腳本在檔案名稱編碼的正確區域設定中運行。

我假設檔案名稱不包含目錄部分。如果有,請先將其分開。

case $filename in
  ?*.*) # There is an extension
    base="${filename%.*}"; ext=".${filename##*.}";;
  *) # No extension
    base="$filename"; ext="";;
esac
upcased_base="$(printf %s. %base | awk '$0 = toupper($0)')"
upcased="${upcased_base%.}$ext"

然後刪除尾隨.部分,確保腳本正確處理檔案名,並在擴展名之前添加換行符。如果沒有這個,命令替換將刪除尾隨的換行符。如果您已經確保檔案名稱不包含換行符,則不需要此操作。%s.$upcased_base

答案3

這是一個完全awk基於 - 的解決方案,您可以將以下行放入 shell 腳本中:

uppercasename="$(echo "$filename" | awk 'BEGIN{FS=OFS="."} NF==1{$1=toupper($1)} {for (i=1;i<NF;i++) $i=toupper($i)} 1')"

這將使用.as 字段分隔符用於輸入和輸出並且,如果只找到一個字段,則將其轉換為大寫,在所有其他情況下,將除最後一個字段之外的所有字段都轉換為大寫。然後它會印出結果(這就是 的意思1,它是 的簡寫符號{print})。

如果您正在使用bash,您可以去掉管道並將其聲明為

uppercasename="$(awk 'BEGIN{FS=OFS="."} NF==1{$1=toupper($1)} {for (i=1;i<NF;i++) $i=toupper($i)} 1' <<< "$filename")"

使用此處字串。

請注意,這是這樣設計的,以便在文件名以 結尾的邊界情況下.(如 中)myfile.this.txt.,它會將其視為“空但存在的後綴”並將其轉換為MYFILE.THIS.TXT..另外,如果檔名開始如果帶有 a.並且沒有其他擴展名(如.myfile),它將保持小寫。

相關內容