🍀【教學】用批次檔跑 Python:用「相對路徑」打造可搬家的自動化流程(新手也看得懂)

一、為什麼我要學「相對路徑」?

很多人在 Windows 上跑 Python 自動化程式時,通常會這樣寫路徑:

C:\Users\me\AppData\Local\Programs\Python\Python39\python.exe D:\DataProject\loader\my_loader.py D:\DataProject\raw\VendorA

看起來沒有錯,但有幾個致命問題:

  1. 專案搬位置就壞掉

    • 例如你把整個專案資料夾搬到 E:\Backup\,這行指令就全掛了。

  2. 換電腦要全部重寫

    • 別人的電腦沒有 D:\DataProject\... 這條路徑,一樣跑不起來。

  3. 排程 / 自動化維護很痛苦

    • 每次路徑改一下,都要重改一堆 script。

所以我們要學的是:

用「相對路徑」+ 一點點批次檔技巧,讓 整包專案可以整個搬走,仍然能自動運作



二、先搞懂:什麼是絕對路徑、相對路徑?

1. 絕對路徑(Absolute Path)

  • 從磁碟機開始寫到檔案為止

  • 例如:

    • C:\Users\me\Documents\report.xlsx

    • D:\DataProject\raw\VendorA\log_20241201.csv

特性

  • 清楚、明確

  • 但只要「任何一小段」資料夾名稱改了,就失效


2. 相對路徑(Relative Path)

相對路徑是「相對於某個基準資料夾」去找檔案。
例如你現在人在這個資料夾:

D:\DataProject\

那下面這些就是「相對路徑」:

  • raw\VendorA\

  • scripts\python\

  • logs\2024\12\

好處是:

只要整個 D:\DataProject\ 這包東西維持內部結構不變,你要把它搬去哪裡都可以。



三、專案結構:先把資料整理好

假設我們做一個「測試資料載入」專案,把 Python、資料、批次檔全部放在一個資料夾裡:

D:\TestLoader\ run_loader.bat ← 主要啟動用的批次檔 data_loader.py ← Python 主程式 data\ ← 放各種資料 IC\process\ VendorA\Raw\ VendorB\Raw\ MOS\process\ VendorA\Summary\ tools\ ExtraLoader.jar ← 如果你還有 Java loader 之類的工具

之後我們要做到的是:

  • 不管這個資料夾叫 D:\TestLoader\ 還是 E:\MyProjects\Loader\

  • 只要 整包一起搬run_loader.bat 一樣可以正常跑


四、重點主角:%~dp0 讓批次檔知道「我在哪裡」

在 Windows 批次檔裡,有一個非常好用的變數:

%~dp0

它代表的是:

目前這支 .bat 檔「所在的磁碟機 + 路徑」


例如:

  • 批次檔位置:D:\TestLoader\run_loader.bat

  • %~dp0 就會是:D:\TestLoader\

所以我們可以這樣寫:

set BASE=%~dp0

之後所有路徑都從 BASE 延伸出去,就變成「相對於批次檔」的路徑了。


五、範例:用批次檔呼叫 Python,全部改用相對路徑

下面是一個簡化版、適合新手看的範例(與你實際專案無關,純示意用):

@echo off setlocal enabledelayedexpansion :: 1. Python 可執行檔位置(你可以改成自己的 Python 位置) set PYTHON_EXE=C:\Python39\python.exe :: 2. 取得這支批次檔所在的資料夾當作專案根目錄 set BASE=%~dp0 :: 3. Python 程式 data_loader.py 就放在同一層 set LOADER=%BASE%data_loader.py :: 4. 資料根目錄(相對於 BASE) set DATA_ROOT=%BASE%data\IC\process\ echo [INFO] 專案根目錄:%BASE% echo [INFO] Python 程式:%LOADER% echo [INFO] 資料根目錄:%DATA_ROOT% :: 5. 載入 VendorA 的資料(相對路徑串成絕對) call "%PYTHON_EXE%" "%LOADER%" --vendor=VendorA --type=IC "%DATA_ROOT%VendorA\Raw" :: 6. 載入 VendorB 的資料 call "%PYTHON_EXE%" "%LOADER%" --vendor=VendorB --type=IC "%DATA_ROOT%VendorB\Raw" echo [INFO] 所有載入流程已完成。 pause endlocal

這段做了什麼?

  1. set BASE=%~dp0

    • 讓批次檔永遠知道「自己在哪個資料夾」

  2. set LOADER=%BASE%data_loader.py

    • 不寫死 D:\...,而是「就在我旁邊那支 Python」

  3. set DATA_ROOT=%BASE%data\IC\process\

    • 所有資料都相對於專案根目錄(BASE)來找

  4. 最後 call Python 時,把 vendor 資料夾路徑串起來:

    "%DATA_ROOT%VendorA\Raw"

    不管你把整個 TestLoader 資料夾搬去哪裡,
    只要結構不變,都能找到同樣的資料。


六、Python 端簡單配合:接收路徑參數就好

接著,我們用一個非常簡化的 data_loader.py 來示範(程式碼完全是示意,不會使用你的實際邏輯):

import argparse from pathlib import Path def load_data(vendor: str, product_type: str, folder: Path): print(f"[INFO] Vendor = {vendor}, Type = {product_type}") print(f"[INFO] Data folder = {folder}") if not folder.exists(): print("[ERROR] 資料夾不存在,請確認路徑是否正確。") return csv_files = list(folder.rglob("*.csv")) if not csv_files: print("[WARN] 找不到任何 CSV 檔,結束。") return for f in csv_files: print(f"[INFO] 處理檔案:{f}") # 在這裡放你真正的處理邏輯(讀取、清洗、寫入資料庫等等) # 例如:pd.read_csv(f) → to_sql(...) def main(): parser = argparse.ArgumentParser() parser.add_argument("--vendor", required=True) parser.add_argument("--type", required=True) parser.add_argument("data_folder", help="要處理的資料夾路徑") args = parser.parse_args() folder = Path(args.data_folder).resolve() load_data(args.vendor, args.type, folder) if __name__ == "__main__": main()

核心概念

  • 批次檔負責:「決定哪個資料夾 要被處理」

  • Python 負責:「怎麼處理裡面的檔案

兩邊靠「路徑」溝通,而這個路徑是從 %~dp0 出發組出來的,所以整包可搬家。


七、進階:一個批次檔處理多種產品 / 資料型態

如果你的專案同時有 IC、MOS、彙總檔、原始檔等等,也可以在同一支批次檔裡,用不同的根目錄變數來管理,例如:

:: 專案根目錄 set BASE=%~dp0 :: IC 資料 set IC_ROOT=%BASE%data\IC\process\ :: MOS 資料 set MOS_ROOT=%BASE%data\MOS\process\ :: 叫 Python 處理 IC VendorA call "%PYTHON_EXE%" "%LOADER%" --vendor=VendorA --type=IC "%IC_ROOT%VendorA\Raw" :: 叫 Python 處理 MOS VendorA Summary call "%PYTHON_EXE%" "%LOADER%" --vendor=VendorA --type=MOS "%MOS_ROOT%VendorA\Summary"

這樣一來:

  • 多個產品線(IC / MOS)

  • 多種資料來源(Raw / Summary)

  • 不用寫死任何 C:\D:\ 的長路徑
    整包 ZIP 給別人、搬到伺服器都好處理


八、常見問題 Q&A

Q1:那 Python 程式裡還需要寫絕對路徑嗎?

建議是不要。

  • 讓批次檔統一決定「入口路徑」,Python 就專心處理「相對於入口」的東西。

  • 真的要寫的話,也用 pathlib.Path 去接、去組合,而不是硬打 C:\...


Q2:這樣可以搭配排程(排程工作)嗎?

可以。實務上很推薦這樣做:

  1. Windows 排程器只跑一個批次檔:

    • C:\Scripts\run_loader.bat

  2. run_loader.bat 自己透過 %~dp0 找到專案根目錄、Python、資料夾

  3. 專案搬位置 → 只要更新「那個批次檔的位置」,內部不用改


Q3:如果未來換 Python 版本怎麼辦?

只要在批次檔改這一行就好:

set PYTHON_EXE=C:\Python311\python.exe

你不用去改每一行 python ... 指令,只改一個變數即可。


九、總結:只要記住這三個關鍵

  1. 專案打包觀念

    • 把 Python 程式、資料、批次檔都放在同一個專案資料夾裡。

  2. %~dp0 當作專案根目錄

    • set BASE=%~dp0 → 後面所有路徑都從 BASE 開始長。

  3. 批次檔負責「路徑」,Python 負責「邏輯」

    • 這樣專案可讀性高、可維護、可搬家。

如果你之後想把這套東西擴充成:

  • 讀 STDF 檔

  • 讀 MDB / Excel 檔

  • 載入到資料庫(SQL Server / PostgreSQL 等)

只要維持同樣的「專案結構 + 相對路徑設計」,修改起來都會輕鬆很多。

留言

這個網誌中的熱門文章

🔍Vue.js 專案錯誤排查:解決 numericFields is not defined 與合併儲存格邏輯最佳化

🔎EF Core 連 Oracle 出現 ORA-00600 [kpp_concatq:2] 的完整排錯指南(含 EF Core ToString/CultureInfo 錯誤)

🛠【ASP.NET Core + Oracle】解決 ORA-00904 "FALSE": 無效的 ID 錯誤與資料欄位動態插入顯示問題