自動目錄
<此文是札記方式寫的文章,如果想直接用程式請滑到最下面>
Git 是很好用的版本控制程式,但我沒辦法使用。
原因就是資安。anyway,我遇到棘手的問題:
A機是我的測試和開發機,我在測試機寫好的程式,要經過很複雜的程序搬到B機的臨時目錄上,再到B機上一個個copy到指定的位置。
如果要這樣做,我有兩個方法處理,一個就是把 A機的所有目錄檔案壓縮搬到B 機,另一個方式就是把異動過的檔案取出來,再手動一個個搬。
事實上,因為是分散效能的關係,我要操作同樣的動作到 CDE機上,不但有可能遺漏,還有可能搬錯,而且很費精神。
所以我想一個方法
[在A機中]
步1 如果我的一個檔案異動清單 diff.txt,寫一個 SHELL 讓清單中的檔案從來源目錄 ./srcwww/ 拷背到目的目錄 ./modwww/ 中指定的位置
步2 我再將這個 ./modwww/ 目錄打包連同 diff.txt 搬移到 B機的臨時目錄中。
[在B機中]
步3 解包並執行 SHELL 讓異動的檔案搬到正式的目錄 ./targwww/ 中
完美~~附帶功能:
- 目的路徑中若資料夾不存在,就自動建立
- 如果檔案不存在,會顯示警告但不會中止
- 如果目標檔案在 ./targwww/ 已經存在,會自動備份到 ./backup/ 目錄(也保留原始路徑結構)
- diff.txt 不存在就停止
程式碼 copy_diff_to_www.sh 初版
#!/bin/bash
# 設定來源根目錄與檔案清單、目標根目錄
source_root="./html"
diff_file="diff.txt"
target_root="/home/axer/web"
backup_root="./backup"
if [ ! -f diff.txt ]; then
echo "檔案 diff.txt 不存在,停止執行。"
echo "你可以下指令來產生這個檔 git diff --name-only <logid> HEAD > diff.txt"
exit 1
fi
# 一行一行處理 diff.txt
while IFS= read -r filepath; do
# 組合完整路徑
src_file="$source_root/$filepath"
target_file="$target_root/$filepath"
backup_file="$backup_root/$filepath"
target_dir="$(dirname "$target_file")"
backup_dir="$(dirname "$backup_file")"
# 檢查來源檔案是否存在
if [ -f "$src_file" ]; then
# 若目標檔案已存在,先備份
if [ -f "$target_file" ]; then
mkdir -p "$backup_dir"
cp "$target_file" "$backup_file"
echo "???? 已備份舊檔:$target_file → $backup_file"
fi
# 建立目標資料夾
mkdir -p "$target_dir"
cp "$src_file" "$target_file"
echo "✔ 拷貝 $src_file → $target_file"
else
echo "⚠ 檔案不存在:$src_file"
fi
done < "$diff_file"
$ chmod 711 copy_diff_to_www.sh
然後和 diff.txt 放在同一個目錄下即可。
產生差異檔案 diff.txt 並執行
重點來了要怎麼產生?一個個打嗎?別擔心,在測試機上可以使用 git。
diff.txt 的產生方法
# git diff --name-only <commit id> HEAD > diff.txt
或是只取回 ACM三種狀態的檔案進行複製。
A:新增 (Added)
C:複製 (Copied)
M:修改 (Modified)
D:刪除 (Deleted)
# git diff --name-only --diff-filter=ACM <commit id> HEAD > diff.txt
這樣會產生從commit id到現在所有非刪除異動的檔案
指令範例
# git diff --name-only f0bc55e7ab53e0523581526e52c541c23fc48332 HEAD > diff.txt
diff.txt 內容範例如下
book/comic/reading.php
noval/appusers/moving_export.php
book/roles/notice.php
theme/img/pic_login.jpg
...清單略...
修改目錄的參數後執行即可
# 設定來源根目錄與檔案清單、目標根目錄
source_root="./srcwww"
diff_file="diff.txt"
target_root="./tagwww"
目錄是相對於此 shell 所在的位置,你也可以用絕對位置
執行
./copy_diff_to_www.sh
▒▒▒▒▒▒▒▒ 重新思考的分隔線 ▒▒▒▒▒▒▒▒▒▒▒▒
那刪除呢?是不是目的有這個檔也要把他刪除,這樣打包時就不會帶上他。
另外,只要目的原本有舊的檔案,無論是異動或是刪除,都要先備份,備份不應全部丟在一個目錄壓來壓去,應該以日期作為區隔。
所以程式特色改成這樣:
- 目的路徑中若資料夾不存在,就自動建立
- 如果檔案不存在,會顯示警告但不會中止
- 如果目標檔案在 ./targwww/ 已經存在,會自動備份到 ./backup/ 目錄(也保留原始路徑結構)
- diff.txt 不存在就停止
- 考慮檔案的異動狀態
程式碼 copy_diff_to_www.sh 終版
#!/bin/bash
# 設定來源與目標根目錄
source_root="/newwww"
target_root="./www"
# 取得當前日期,用於備份子資料夾
today=$(date +%F) # 格式:2025-07-03
backup_root="./backup/$today"
diff_file="diff.txt"
# 檢查清單檔是否存在
if [ ! -f "$diff_file" ]; then
echo "❌ 檔案 $diff_file 不存在,停止執行"
exit 1
fi
# 處理每一行
while IFS=$'\t' read -r change_type filepath; do
# 忽略空行
if [[ -z "$filepath" ]]; then
continue
fi
src_file="$source_root/$filepath"
target_file="$target_root/$filepath"
backup_file="$backup_root/$filepath"
target_dir="$(dirname "$target_file")"
backup_dir="$(dirname "$backup_file")"
case "$change_type" in
A|M|C)
# 來源檔案存在才處理
if [ -f "$src_file" ]; then
# 若目標檔案存在,先備份
if [ -f "$target_file" ]; then
mkdir -p "$backup_dir"
cp "$target_file" "$backup_file"
echo "???? 已備份舊檔:$target_file → $backup_file"
fi
# 建立目標資料夾並拷貝
mkdir -p "$target_dir"
cp "$src_file" "$target_file"
echo "✔ 拷貝 $src_file → $target_file"
else
echo "⚠ 檔案不存在於來源:$src_file"
fi
;;
D)
if [ -f "$target_file" ]; then
mkdir -p "$backup_dir"
cp "$target_file" "$backup_file"
rm "$target_file"
echo "❌ 刪除 $target_file(已備份至 $backup_file)"
else
echo "⚠ 刪除項目不存在於目的地:$target_file"
fi
;;
*)
echo "❓ 未知變更類型:$change_type $filepath"
;;
esac
done < "$diff_file"
產生有異動狀態的 diff.txt
# git diff --name-status --diff-filter=ACM <commit id> HEAD > diff.txt
# git diff --name-status f0bc55e7ab53e0523581526e52c541c23fc48332 HEAD > diff.txt
diff.txt 的範例:
其中第一個字元是異動狀態,接著一個 \t ,然後是檔名。
執行結果範例:
所以最後我的方案是:
[在A機中]
步1 產生異動 diff.txt,執行這個 SHELL 產生一個 ./modwww
步2 將這個 ./modwww/ 目錄打包連同 diff.txt 搬移到 B機的臨時目錄中。
tar -czf modwww.tar.gz ./modwww
[在B機中]
步3 解包並執行 SHELL 讓異動的檔案搬到正式的目錄 ./targwww/ 中
tar -xzf modwww.tar.gz
備份檔目錄
備份加上日期分隔,非常棒:
└── 2025-07-09
├── config
├── experiment
├── lib
├── login.php
└── theme
有異動的才會出現,方便還原。
結論
感謝 AI,讚嘆AI
程式都是 CHATGPT 寫的,我是個廢物。