[精讚] [會員登入]
5

[BASH] 自建檔案拷背程式--把指定的檔案拷背到指定的位置。

Git 是很好用的版本控制程式,但我沒辦法使用。 原因就是資安。用SHELL自建簡易的GIT

分享此文連結 //n.sfs.tw/16531

分享連結 [BASH] 自建檔案拷背程式--把指定的檔案拷背到指定的位置。@新精讚
(文章歡迎轉載,務必尊重版權註明連結來源)
2025-07-09 03:21:14 最後編修
2025-07-09 02:23:53 By 張○○
 

自動目錄

<此文是札記方式寫的文章,如果想直接用程式請滑到最下面>

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 內容範例如下

note/appusers/getstat.php
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

 

備份檔目錄

備份加上日期分隔,非常棒:

backup/
└── 2025-07-09
    ├── config
    ├── experiment
    ├── lib
    ├── login.php
    └── theme

有異動的才會出現,方便還原。

 

結論

感謝 AI,讚嘆AI

程式都是 CHATGPT 寫的,我是個廢物。

 

 

END

你可能感興趣的文章

SELinux 常用指令和檔案 在Redhat系列中,Centos5以後加入了selinux,他並沒有這麼可怕,不必每次看到Selinux ,就想把他

[CentOS] 設定和使用quota quota 的觀念已經很老了,不過每次都會忘記所以寫下來,有需要觀念的朋友請參看鳥哥的網站吧

[Centos] opentftp + selinux 安裝及設定 Centos 安裝微型ftp伺服器:tftp伺服器

[Centos8] 安裝phpMyAdmin Centos 8目前只能採用tarball安裝法

[Centos7] HTTPS/SSL憑證的SELINUX設置 把申請來的憑證檔放到指定的位置後,沒辦法啟動,怎麼辦?

[Rocky9] 安裝SPHINX Search 3 支援中文 新版本的 sphinx 和舊版不同,網路上很多範例和教學是不能用的。此文是安裝和設定方法分享

我有話要說

>>

限制:留言最高字數1000字。 限制:未登入訪客,每則留言間隔需超過10分鐘,每日最多5則留言。

訪客留言

[無留言]

隨機好文

使用Google尋找你的手機 這近發現google竟然可以用來找android的手機,而且不需要經過什麼設定或安裝軟體。

為什麼要買長達二十年的保單? 為什麼要買長達二十年的保單?找一個可以說服我買二十年保單的理由。

[PHP] 檢查檔案是否是圖檔 使用getimagesize函數檢查檔案是否是圖檔

設計的工作絕不接受比價 拿買陽春麵的價格想買牛肉麵,寧願倒掉也不賣

[大型機台] 熱血高校躲避球 多少少年時光歲月耗在這個遊戲上,二十幾年前的那個時光,唯一想做的事就是把吃飯錢省下來拿去打一場五塊錢的電動,就算是沒錢也