在 shell 腳本程式中,如果轉換後的檔案名稱尚不存在,我需要將檔案名稱轉換為大寫。在這種特殊情況下,我只需將基本名稱更改為大寫,保留擴展名(如果有)不變。
我解決這個問題的想法是首先分別提取基本名稱和擴展名,使用
tr
命令將基本名稱轉換為大寫,然後檢查目錄中是否存在更改的基本名稱和擴展名。
如果它不存在,那麼我將使用 mv 將原始檔案名稱更改為大寫基本名稱。現在我認為這可以透過兩種方式完成:首先使用expr
,其次是使用cut
with .
(space-period-space) 作為分隔符號。
如果我想用於expr
提取基本名稱(例如從文件名 -python1.py
或phonelist
),那麼我寫了這個:
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 參數操作更容易。
在轉換為大寫時,請注意tr
Linux 上的實作不支援非 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
),它將保持小寫。