
我有一個包含多個文件的資料夾,格式如下:
C Block Scan copy 1.pdf
C Block Scan copy 2.pdf
C Block Scan copy 3.pdf
C Block Scan copy 4.pdf
.
.
.
我遇到的一個問題是,當我運行時ls
,Unix 將它們列為
C Block Scan copy 1.pdf
C Block Scan copy 10.pdf
C Block Scan copy 11.pdf
C Block Scan copy 12.pdf
.
.
.
我想填充數字,以便 Unix (希望)按順序列出它們
C Block Scan copy 01.pdf
C Block Scan copy 02.pdf
C Block Scan copy 03.pdf
.
.
.
C Block Scan copy 09.pdf
C Block Scan copy 10.pdf
C Block Scan copy 11.pdf
C Block Scan copy 12.pdf
.
.
.
發現一個貼文也有類似的問題將檔案名稱中的數字填入固定長度,但我嘗試將他們的解決方案應用於我的案例,但無法使其發揮作用。這是我嘗試過的:
for f in *.pdf; do
int=`basename $f .pdf | cut -d '.' -f 2`
new_name=`printf "file.%0.2i.pdf\n” $int`
[ ! -f $new_name ] && mv $f $new_name
done
我承認這是他們對我的情況的解決方案的盲目適應,我不喜歡這樣做,因為我並不真正理解底層語法,而且我在 StackExchange 上的排名還沒有足夠高,無法評論該帖子。
我是 shell 腳本編寫的新手,因此對語法含義的解釋會很有幫助並且值得讚賞。
如果有幫助的話,我使用的是 macOS Mojave 10.14.6,並且安裝了 Brew。
提前致謝。
答案1
使用zsh
(現在是 macOS 上的預設使用者 shell):
autoload zmv # best in ~/.zshrc
zmv '(* )([0-9].pdf)' '${1}0$2'
答案2
這將查找當前目錄中名稱遵循問題中描述的模式的所有“*.pdf”檔案並將其重命名為相同名稱,但數字填入 2 位數字:
#!/usr/bin/env bash
shopt -s nullglob
for f in *[[:space:]][0-9].pdf; do
int="$(basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1)"
name="$(basename "$f" | rev | cut -d ' ' -f2- | rev)"
padded_int="$(printf "%02d\n" "$int")"
echo mv "$f" "$(printf "%s %s.pdf" "$name" "$padded_int")"
done
在實際運行echo
之前刪除它,但首先按原樣運行它,以確保它執行您希望它執行的操作。將上述腳本儲存到的範例用法:mv
mv
pdf.sh
$ for i in {1..10}; do touch "C Block Scan copy $i.pdf"; done
$ ./pdf.sh
mv C Block Scan copy 1.pdf C Block Scan copy 01.pdf
mv C Block Scan copy 2.pdf C Block Scan copy 02.pdf
mv C Block Scan copy 3.pdf C Block Scan copy 03.pdf
mv C Block Scan copy 4.pdf C Block Scan copy 04.pdf
mv C Block Scan copy 5.pdf C Block Scan copy 05.pdf
mv C Block Scan copy 6.pdf C Block Scan copy 06.pdf
mv C Block Scan copy 7.pdf C Block Scan copy 07.pdf
mv C Block Scan copy 8.pdf C Block Scan copy 08.pdf
mv C Block Scan copy 9.pdf C Block Scan copy 09.pdf
第一行:
#!/usr/bin/env bash
這條線
shopt -s nullglob
套空球 外殼選項 連結網站上也對此進行了解釋:
nullglob
If set, Bash allows filename patterns which match no files to
expand to a null string, rather than themselves.
如果沒有與模式條件相符的文件,則需要防止 for 迴圈啟動:
for f in *[[:space:]][0-9].pdf; do
*[[:space:]][0-9].pdf
是一種 shell 模式,意味著查找名稱由任意數量的字元組成的文件,後面跟著一個空格,後面跟著一個數字,並以.pdf。循環內部$f
將保存已處理的 .pdf 檔案的名稱。
這裡
int="$(basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1)"
我們用命令替換
將給定檔案名稱的整數部分指派給變數。您可以在終端機basename
中查看man basename
並重現管道中的內容:
$ f='C Block Scan copy 1.pdf'
$ echo basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1
1
$ f='C Block Scan copy 5.pdf'
$ echo basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1
5
(請注意,$
這裡有一個命令列提示符
用於指示新行的開始,而不是命令的一部分)。
在下一行
name="$(basename "$f" | rev | cut -d ' ' -f2- | rev)"
我們提取 .pdf 的名稱部分,即數字之前的所有內容。
在下一行
padded_int="$(printf "%02d\n" "$int")"
我們使用 Bash 內建printf
命令來填充$int
並將其保存到名為 的變數中padded_int
。在迴圈的最後一行
echo mv "$f" "$(printf "%s %s.pdf" "$name" "$padded_int")"
我們再次運行(echo
當然沒有)使用命令替換的實際重命名printf
。 printf
與 2 個格式說明符和 2 個對應的參數一起使用%s
,與 C 中類似。
最後一行
done
關閉循環。
答案3
使用PE參數擴展。僅mv
適用於 shell 中的外部工具bash
。
#!/usr/bin/env bash
shopt -s nullglob
for f in *[[:space:]][0-9].pdf; do
n=${f##* } ##: Remain only 1.pdf, 2.pdf etc.
n=0${n%.*} ##: Remain only 1 , 2 etc. and pad 0 so it will be 01, 02 ..
echo mv -v "$f" "${f/[0-9]/"$n"}" ##: Replace all [0-9] with the value of "$n"
done
- 看參數擴充