今天同學有一個批量改文件夾名字的需求,因為非計算機專業的同學電腦肯定不會有 python 或者 java 的環境了,那麼 windows 自帶的批處理編程一定是最好的選擇了,新建一個 .txt,改後綴命為 .bat,雙擊就可以運行了。
利用批處理的一些命令,可以做很多事情,之前在知乎回答過一個問題,一行代碼可以做什麼。
https://www.zhihu.com/question/285586045/answer/445364909
裡邊提到了鎖屏和 windows 計劃任務的結合。
rundll32.exe user32.dll,LockWorkStation
定時關機,1800 秒後關機。
shutdown -s -t 1800
他想把很多個文件夾的名字從 abcd1233-afdasfs 改成 1233 abcd1233-afdasfs,所有文件夾的格式都是 4個字母,4 個數字,然後一個-,最後再跟一些字符。需要做的就是把4個數字添加到文件夾名字的最前面,並且跟一個空格。
嘗試一我也是第一次寫批處理的程序,但是不慌,編程嘛,重要的是算法,語言的語法查一查就可以了。所以需要解決下邊幾個問題。
定義變量
set name=XXX
注意的是,默認賦值就是賦值字符串,而且也不用加雙引號
如果想賦值數字,需要再 set 後邊添加命令參數 /a。
set /a num=1
取出變量的值,百分號包裹變量名
%name%
輸出變量的值
echo %name%
for循環遍歷所有文件夾名,所有變量都保存在了 %%i變量裡,至於為啥加了兩百分號,不要問,問的話,我也不知道 2333,就是規定而已。此外加了 /d 命令參數,表示遍歷文件夾
for /d %%i in (*) do (
因為我們要取到文件夾名字中的數字,所以要進行切割
set newname=%name:~4,4%
語法就是,字符串變量加冒號加~,然後兩個數字的含義分別是字符串開始的位置以及字符的個數,開始位置從零開始計數
更改文件夾名字
ren oldname newname
還有一個一定會用的,注釋代碼
兩種, :: 加語句,或者 rem 加語句,推薦rem吧,因為:: 我遇到了不知道什麼原因的錯誤。
知道了上邊的一切,就可以寫出代碼了,但寫完之後發現個問題,我們用 %name%並不能得到變量的值,查了查,原來在 for 循環中要用 !name!。並且開頭加上setlocal enabledelayedexpansion。
rem ehco 設置為 off,不然的話運行會顯示每條語句
@echo off
rem 防止中文亂碼的
chcp 65001
setlocal enabledelayedexpansion
for /d %%i in (*) do (
set name=%%i
echo !name!
rem 字符串合併,四個數字加上空格再加上之前的名字,不用雙引號
set newname=!name:~4,4! !name!
rem 因為 newname 中有空格,所以要加雙引號
ren !name! "!newname!"
)
echo 處理完成
pause
假如我們有下邊的文件夾
然後把上邊的代碼複製保存為 .bat,執行
很完美,達到預期。
問題升級寫完代碼以後和同學確認了一下需求,出現了一個問題,有的文件夾名字是 (啊)abcd1233-afdasfs 、(啊啊)abcd1233-afdasfs 這樣的形式,也就是說數字開始的位置不一定是 4 了。怎麼辦呢?
嘗試二我們只要知道 - 的下標,往前數 4 個數字就可以了,沒有找到什麼直接的方法,找到一種利用 goto 的方案。
goto 語法就是先用 :label定義一個位置,然後 goto label 就可以實現循環了。
所以我們的想法就是遍歷文件夾的名字的字符串,得到 - 的位置。
@echo off
chcp 65001
setlocal enabledelayedexpansion
for /d %%i in (*) do (
set name=%%i
echo !name!
set str=%%i
set /a num=0
:next
if not !str!=="" (
set /a num+=1
if "!str:~0,1!"=="-" goto last
set str=!str:~1!
goto next
)
set /a num=0
:last
echo 字符-在字符串"!name!"中的首次出現位置為!num!
set newname=!name:~4,4! !name!
)
echo 處理完成
pause
理想是美滿的,現實是殘酷的,本以為解決了,然後運行測試了一下。
比如我們有下邊樣子的文件夾
然後把上邊的代碼保存成 .bat 執行會發現結果是下邊的樣子
- 的位置找對了,但是…為什麼只找了一次,我們的for循環怎麼沒用了 。
幾經試探,搜索。發現微軟的批處理命令不知道基於什麼考慮,如果我們在 for 循環中用了 goto,那麼 for 循環就會自動結束。沒辦法,我們得換思路了。
最終嘗試網上找了找,找到一種截取某一個字符前的字符串的方法。
for /f "delims=-" %%n in ('echo %%i') do (
)
這裡的 %%n 就會保存 - 前邊的字符串了。然後我們保存倒數四個的字符串就可以了。而倒數其實也提供了方法。
截取通過倒數方式指定開始位置的整個字符串:%key:~-2%,表示截取從倒數第 2 個字符開始的整個字符串
正數倒數方式相結合:%key:~2,-2%,表示截取從下標 2 開始到倒數第 2 個之間的字符串
所以我們最後的代碼就是下邊的了,注意用等號賦值的時候可能習慣左右加空格,這裡就不要加了,會出錯。
@echo off
chcp 65001
setlocal enabledelayedexpansion
for /d %%i in (*) do (
echo %%i
rem set newname=%%i
for /f "delims=-" %%n in ('echo %%i') do (
set name=%%n
set newname=!name:~-4! %%i
)
ren "%%i" "!newname!"
)
echo 處理完成
pause
執行前的文件夾
執行上邊的代碼
執行後的文件夾
完美!
結束大功告成了。只能說批處理的命令坑太多了,非常不習慣,和現代程式語言太多的不同了。唯一的好處就是不用搭環境,寫個文本文件直接運行。但對於這些文件處理,推薦學一下 python ,就會體會到優雅了。
另外知乎之前回答的那個一句代碼實現鎖屏的效果如下。
然後和 windows 的計劃任務結合,每隔一小時執行,就可以作為簡單的定時休息了,具體方法點擊閱讀原文可以到知乎看一下。