無人值守自動傳輸)
簡介圍繞批處理命令與FTP自動傳輸整理的Word文檔面向Windows及UNIX環(huán)境下的系統(tǒng)運維人員和網(wǎng)絡管理員用于解決每天重復登錄、手工收發(fā)文件既繁瑣又容易出錯的問題。文檔以1.ftp與1.bat兩個文本的編寫為主線說明如何用 ftp -n -s 參數(shù)靜默調(diào)用腳本如何取舍二進制與ASCII兩種傳輸模式如何用Mget與Mput完成收發(fā)切換并把批處理加入“任務計劃”按周期自動執(zhí)行同時給出UNIX下shell腳本的寫法與可執(zhí)行權限設置便于跨平臺對照。包內(nèi)共1個doc文件約44KB正文含腳本片段、步驟說明與應用案例可直接當模板改造使用。已有2121人學習適合需要搭建定時傳輸任務、減少人工干預的初、中級運維讀者參考。1. 兩個文本文件替代一個定時任務這套 FTP 自動傳輸方案的定位半夜兩點半一臺常開的 Windows 機器要從對端拉走當天的數(shù)據(jù)文件第二天早上八點前必須到位。這個需求用「批處理命令實現(xiàn) FTP 文件的自動傳輸」是最省事的解法一個.ftp文件寫會話命令一個.bat文件切目錄并把腳本傳給ftp.exe最后交給系統(tǒng)自帶的任務計劃按周期觸發(fā)。全程不裝任何軟件運行時就是C:\Windows\System32\ftp.exe。適合的場景很明確Windows 常開、對端是 UNIX 或另一臺 Windows、文件量幾十到幾百個、總量幾百 MB 以內(nèi)、對端只提供標準 FTP。不適合的同樣明確要斷點續(xù)傳、要加密鏈路、要做復雜重試和告警。下面按「腳本怎么寫 → 批處理怎么包裝 → 計劃任務怎么掛 → 哪里會翻車」拆開說。2. 拆 1.ftp從 open 到 bye 的九行命令每行都在決定成敗2.1 腳本文件的本質(zhì)是把鍵盤輸入重定向成文件ftp.exe本身是個交互式程序你在提示符下敲open、user、cd它讀一行執(zhí)行一行。-s:文件名做的事只有一件把標準輸入從這個文件讀而不是從鍵盤讀。所以腳本里能寫什么完全取決于客戶端在交互模式下認什么命令沒有額外語法沒有變量替換沒有 if 判斷也沒有循環(huán)。這一點想明白后面很多「為什么我寫了變量它不認」的疑問就自然消失了。把原料里的腳本攤開看實際長這樣open 10.30.15.3 user anonymous 123456 cd data bin prompt mget *.* bye quit exitopen建立控制連接默認端口 21如果對端改了端口就寫成open 10.30.15.3 2121。user后面跟用戶名和密碼這一行實際對應 FTP 協(xié)議里的 USER 和 PASS 兩條命令密碼不寫在user同一行也可以下一行單獨寫客戶端會把它當 PASS 發(fā)出去。但要注意如果user后面只寫了用戶名、下一行又忘了寫密碼客戶端會當場停在Password:提示上等人輸入無人值守場景下就是一直掛著直到超時。bye、quit、exit三個是同一個意思都是發(fā) QUIT 并斷開。寫一個就夠多寫不報錯但日志里會多出一段無意義的響應。原料里三行都寫了這屬于「寫了也沒壞處但沒必要」。真正需要留意的是cd data這一行cd切的是遠端目錄本地目錄要靠lcd或者批處理里的cd來處理這兩個概念在初學時最容易混。2.2 bin 與 ascii模式選錯文件看著傳完了其實是壞的bin是binary的縮寫對應 FTP 協(xié)議的TYPE I不寫這一行Windows 客戶端默認走TYPE A也就是 ASCII 模式。兩者的差別不在速度在于是否對字節(jié)做轉(zhuǎn)換。ASCII 模式會按行處理把本地的行尾轉(zhuǎn)成網(wǎng)絡標準 CRLF對端再轉(zhuǎn)成自己的行尾二進制模式逐字節(jié)搬運一個字節(jié)都不動。原料里有一句「如果是 Windows 之間傳去掉 bin 一行就可以了」這話得辯證看。兩臺 Windows 之間傳純文本ASCII 模式確實能正常工作因為兩邊的行尾都是 CRLF來回轉(zhuǎn)換等于沒轉(zhuǎn)。但一旦傳的是壓縮包、可執(zhí)行文件、數(shù)據(jù)庫備份去掉bin就是災難——ASCII 模式會把文件里恰好出現(xiàn)的0x0D、0x0A字節(jié)當成行尾改寫傳完大小對不上解壓報 CRC 錯誤備份文件恢復不了。更麻煩的是這種損壞不會當場報錯日志里照樣是226 Transfer complete等你去恢復數(shù)據(jù)的時候才發(fā)現(xiàn)。按文件類型選模式的對照關系我一般按這張表來定文件類型傳輸模式選錯的后果.txt/.csv/.log/.sqlascii用 bin 傳UNIX 端每行末尾多個^M解析腳本讀出錯位.zip/.rar/.7z/.gzbin用 ascii 傳壓縮包損壞解壓直接報錯.exe/.dll/.sobin用 ascii 傳可執(zhí)行文件加載失敗.dmp/.bak數(shù)據(jù)庫備份bin用 ascii 傳備份集無法恢復且不易察覺.jpg/.png/.pdfbin用 ascii 傳圖片花屏、PDF 打不開實操上的做法是按方向拆腳本而不是在一個腳本里來回切模式。收文本一個.ftp收二進制另一個.ftp各自在自己那個腳本開頭寫死模式?;煸谝粋€腳本里也不是不行ascii和bin可以在會話中反復切換但腳本一長就容易出現(xiàn)「切過去忘了切回來」的問題排查起來很費勁。2.3 prompt 與 mget/mput通配符的兩次展開和確認開關prompt在 Windows 客戶端里是個切換開關敲一次關掉交互確認再敲一次打開。關掉之后mget一次匹配到十個文件也不會逐個問mget xxx?。不寫這一行的后果在無人值守場景下很直觀任務計劃狀態(tài)一直顯示「正在運行」日志停在一長串mget a.txt?上等到超時才退出一個文件都沒傳下來。原料里把prompt放在mget前面順序是對的這個順序不能反。mget *.*里的通配符不是客戶端在本地展開的而是原樣發(fā)給服務器由服務器的NLST或LIST來匹配。這帶來兩個邊界。第一*.*在多數(shù) UNIX 服務端只能匹配「文件名里帶點」的文件像README、Makefile這種不帶點的文件匹配不到要改成mget *。第二mget不遞歸遠端data目錄下的子目錄里的文件不會被帶下來真要按層級收常見做法是一個子目錄寫一個cdmget段落或者干脆在對端先打包成一個文件再傳。發(fā)送方向同理把mget換成mputcd換成遠端的上傳目標目錄本地目錄靠lcd指定。一個改好之后可直接抄的版本open 10.30.15.3 user anonymous 123456 binary prompt lcd C:\datatran cd data mget *.txt mget *.csv byelcd這一行很多示例里不寫靠批處理里的cd來兜底。兩種做法都行但顯式寫lcd更穩(wěn)因為批處理的當前目錄會被任務計劃的「起始于」字段影響而lcd是寫死在腳本里的絕對路徑不受外部干擾。密碼和用戶名并到user一行也建議這么改少一行就少一個錯位的機會。3. 1.bat 的封裝層ftp -n -s 幾個參數(shù)各自在擋什么3.1 -n 不是「不登錄」是「不要自動匿名登錄」批處理這一層看著只有三行但ftp后面那幾個參數(shù)每一個都在解決一個具體問題。先看原料給的寫法C: cd datatran ftp -n -s:c:\1.ftp-n是最容易被誤解的一個。它的準確含義是「啟動時抑制自動登錄」也就是不主動發(fā)USER anonymous去嘗試匿名登錄。如果不加-n客戶端啟動后會先做一次匿名登錄嘗試再執(zhí)行腳本里的open和user結(jié)果是日志里憑空多出一段 331/230 響應某些對失敗次數(shù)敏感的服務端還會因此觸發(fā)限制。腳本里既然已經(jīng)寫死了用戶名密碼-n就應該加上。-s:后面緊跟腳本路徑冒號和文件名之間不能有空格這一點和多數(shù)命令行工具的-s 文件名寫法不一樣。路徑里帶空格的時候用引號包住整個參數(shù)寫成-s:C:\my scripts\1.ftp。原料用的是c:\1.ftp腳本放在盤符根目錄這個習慣在單人環(huán)境里沒問題但放到多臺機器統(tǒng)一部署時最好歸到一個固定目錄比如C:\scripts\否則重裝系統(tǒng)或者換盤符就得挨個改。其余幾個參數(shù)按需加我整理成一張表備查參數(shù)作用什么時候必須加-n禁止啟動時自動匿名登錄腳本里已寫死賬號密碼時-s:file指定命令腳本文件無人值守場景總是-v抑制遠端響應輸出日志要干凈、只留關鍵行時-i多文件傳輸時關閉交互確認腳本里漏寫prompt時的兜底-d打開調(diào)試輸出每條 FTP 命令排查「為什么這條沒執(zhí)行」時臨時加-A強制匿名登錄對端只開放匿名訪問時-w:size設置接收緩沖區(qū)大小大文件吞吐調(diào)優(yōu)一般不用動-i和腳本里的prompt是同一個效果的兩條路徑建議兩個都寫腳本里寫prompt是為了腳本本身獨立可讀命令行加-i是為了別人臨時改腳本時忘寫也不至于卡死。這種「雙保險」在無人值守場景里不算冗余算必要成本。3.2 C: 和 cd批處理的當前目錄才是文件落地的地方C:切盤符cd datatran切目錄這兩行的作用是給后面啟動的ftp.exe定一個當前工作目錄。mget下載下來的文件默認落在當前目錄也就是這兩行切過去的C:\datatran。如果這兩行漏了ftp.exe繼承的是父進程的當前目錄手工雙擊 bat 的時候父進程是資源管理器目錄可能恰好是你想要的一旦掛進任務計劃父進程是taskeng.exe或svchost.exe當前目錄變成C:\Windows\System32文件全落到系統(tǒng)目錄里還因為權限問題寫不進去。更穩(wěn)的寫法是一行到位cd /d C:\datatran/d參數(shù)讓cd同時處理盤符切換和目錄切換不用先寫C:再寫cd。原料里分兩行的寫法在C:盤內(nèi)沒問題但如果哪天目錄換到D:盤只寫cd D:\datatran是不生效的——它只改 D 盤的當前目錄不切當前盤文件還是落在 C 盤。這是個很典型的老坑/d能一次性繞開。目錄切完ftp這一行建議加上輸出重定向把會話日志留到文件里ftp -n -v -s:C:\scripts\1.ftp C:\logs\ftp_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log 21 echo [%TIME%] exit%ERRORLEVEL% C:\logs\ftp_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log是追加避免同一天多次運行互相覆蓋21把錯誤流也并進同一個文件否則連接失敗的提示只會閃一下窗口就沒了。最后那行echo exit%ERRORLEVEL%很關鍵——%ERRORLEVEL%是緊跟上一條命令的退出碼中間隔了別的命令就被覆蓋了所以必須緊貼著寫。3.3 先手工跑通再掛計劃驗證的三個觀察點掛任務計劃之前一定先在命令行里手工跑一遍而且要模擬任務計劃的運行環(huán)境不是在資源管理器里雙擊。打開cmdcd到一個不相干的目錄再執(zhí)行C:\scripts\1.bat這樣才能暴露相對路徑的問題。跑完之后按三個點檢查日志。第一看有沒有230 Login successful沒有的話是賬號、密碼或者對端權限的問題跟腳本后面的命令無關。第二數(shù)226 Transfer complete出現(xiàn)了幾次和遠端目錄里的文件數(shù)對一下少幾個就是通配符沒匹配上或者某個文件被跳過。第三比對一個具體文件的大小本地和對端一致才算真的傳完如果用的是 ASCII 模式傳二進制文件大小可能一致但內(nèi)容已經(jīng)壞了這種情況只能靠校驗和發(fā)現(xiàn)。%DATE%這個變量有個隱性依賴它的格式跟著系統(tǒng)區(qū)域設置走。中文系統(tǒng)默認是2024/05/12 周日這種形態(tài)%DATE:~0,4%取到年份沒問題換成英文系統(tǒng)就是Sun 05/12/2024同樣一段截取取到的是星期幾的縮寫日志文件名直接亂掉。要跨機器部署的話把時間戳換成wmic os get localdatetime或者用 PowerShell 的Get-Date -Format yyyyMMdd更保險別在這個細節(jié)上栽跟頭。4. 掛進任務計劃無人值守必須擰對的三個開關4.1 圖形向?qū)Ш?schtasks 命令行選哪個老系統(tǒng)上的路徑是「開始 → 程序 → 附件 → 系統(tǒng)工具 → 任務計劃 → 添加任務計劃」一路下一步填周期和密碼就完事。新系統(tǒng)Win7 之后改叫「任務計劃程序」在運行框里敲taskschd.msc打開左側(cè)「創(chuàng)建基本任務」適合手工配一次「創(chuàng)建任務」能配的選項更全。圖形界面的好處是能看見每個開關的中文說明壞處是配十臺機器要點十遍。批量部署我一般直接用schtasksschtasks /create /tn FTP_Auto_Transfer /tr cmd /c C:\scripts\1.bat /sc daily /st 02:30 /ru SYSTEM /rl HIGHEST /f參數(shù)逐個對著看參數(shù)含義需要注意的地方/tn任務名同名會沖突配/f直接覆蓋/tr要執(zhí)行的命令路徑帶空格必須用引號建議外套一層cmd /c/sc調(diào)度周期daily / weekly / minute / onlogon / onstart/st開始時間24 小時制 HH:mm不帶秒/mo間隔配/sc minute /mo 15表示每 15 分鐘/ru運行賬戶填 SYSTEM 時不需要密碼/rp賬戶密碼/ru指定普通賬戶時不填會退化成「僅登錄時運行」/rl權限級別HIGHEST 需要當前是管理員/f同名覆蓋不加會彈交互確認腳本里就卡住了/tr外面套cmd /c是刻意為之。任務計劃對「程序路徑」和「參數(shù)」是分開解析的直接寫C:\scripts\1.bat有時會被當成程序名去找路徑里一旦有空格就斷在中間。套一層cmd /c之后整條命令交給命令解釋器處理路徑、重定向、連接符都按批處理的規(guī)則走行為更可控。4.2 「只在用戶登錄時運行」和「不管用戶是否登錄都運行」這一組選項是無人值守能不能成立的分水嶺。圖形界面里在「常規(guī)」選項卡頂部兩個單選按鈕上面那個是「只在用戶登錄時運行」下面那個是「不管用戶是否登錄都運行」。向?qū)J選的是上面那個因為它不需要存密碼。選上面的后果是人一下班注銷任務就停。有些環(huán)境里用戶不注銷、只是鎖屏任務還能跑于是測試的時候一切正常正式跑了一周突然開始抽風——因為中間有人重啟了機器登錄會話沒了。這種「間歇性失敗」最難查因為失敗的時候沒人在現(xiàn)場看。選下面的選項要輸入賬戶密碼密碼存在系統(tǒng)的憑據(jù)存儲里。這里有個后續(xù)麻煩域環(huán)境或者本地安全策略要求定期改密碼密碼一改任務計劃里存的舊密碼就失效任務開始報0x8007052E登錄失敗。要么在改密碼的流程里把任務計劃一起更新要么干脆把運行賬戶換成SYSTEM。SYSTEM的好處是不需要密碼、不受登錄會話影響、權限足夠高。代價是它看到的網(wǎng)絡環(huán)境是機器本身的不是某個登錄用戶的用戶手工映射的網(wǎng)絡驅(qū)動器盤符它一律看不見必須用 UNC 路徑。純 FTP 傳輸不涉及映射盤所以SYSTEM是個很省心的選擇但如果批處理里還要往網(wǎng)絡共享目錄里搬文件就得換回普通賬戶加存密碼的方式。4.3 起始于、失敗重試和「上次運行結(jié)果」圖形界面里「操作」那一頁有個「起始于可選」字段很多人跳過不填。這個字段設的是任務啟動時進程的當前目錄不填的話就是C:\Windows\System32。批處理里如果已經(jīng)寫了cd /d這個字段填不填無所謂如果批處理依賴相對路徑這里必須填否則就是前面說的那種「手工跑正常、計劃跑找不到文件」。schtasks命令行沒有直接對應「起始于」的參數(shù)要設的話得導出 XML 改WorkingDirectory節(jié)點或者把/tr寫成cmd /c cd /d C:\datatran 1.bat。后者更省事也不依賴 XML 的格式版本?!溉绻蝿帐“匆韵骂l率重新啟動」這個設置在 FTP 場景里很有用。對端偶爾網(wǎng)絡抖動、服務端連接數(shù)滿了、DNS 解析慢都會導致一次連接超時重試兩三次基本能覆蓋掉。頻率設 5 分鐘、重試 3 次是個比較穩(wěn)的組合間隔太短會在對端還沒釋放連接的時候又頂上去。跑完之后看「上次運行結(jié)果」那一列幾個常見碼記一下0x0是成功0x1是一般性錯誤通常是腳本里的命令返回了非零0x2是找不到文件路徑寫錯了0x41301是任務正在運行不是錯誤是還沒跑完0x8007052E是登錄失敗密碼失效。看到0x0也別急著放心前面說過FTP 連不上但腳本正常退出退出碼也可能是 0真正的判斷要看日志內(nèi)容。5. 五次真實環(huán)境故障從卡在 y/n 到「只在登錄時運行」下面這幾條都是在這類腳本上真實遇到過的按「現(xiàn)象 → 原因 → 解決」寫遇到類似癥狀可以直接對照。5.1 現(xiàn)象任務狀態(tài)一直「正在運行」日志停在一串mget xxx?原因腳本里漏了promptmget匹配到多個文件時逐個等確認無人值守環(huán)境下沒人敲 y進程一直掛著直到超時退出。原料里的腳本是有prompt的但很多人抄的時候只抄了open、user、cd、mget、bye幾行把prompt和bin當成可選行略掉了。解決腳本里mget之前必須有一行prompt命令行再加-i做兜底。已經(jīng)卡住的任務要在任務計劃里手動「結(jié)束」掉否則下一次觸發(fā)會因為「任務已在運行」被跳過看起來像是徹底不跑了。5.2 現(xiàn)象手工雙擊 bat 一切正常掛進計劃就報「找不到文件」原因兩種可能。一是批處理里沒有cd /d任務計劃的當前目錄是System32相對路徑全部失效。二是任務計劃的「起始于」為空而 bat 里引用腳本時用了相對路徑比如-s:1.ftp而不是-s:C:\scripts\1.ftp。解決bat 第一行寫cd /d C:\datatran腳本路徑一律用絕對路徑/tr外面套cmd /c。三件事一起做這類問題基本不再出現(xiàn)。5.3 現(xiàn)象壓縮包傳過去解壓報 CRC 錯誤但文件大小差不多原因用了 ASCII 模式傳二進制文件。原料里那句「Windows 之間傳就去掉 bin」被照搬到所有場景結(jié)果傳的是 zip、dmp、exe。ASCII 模式把文件里恰好出現(xiàn)的0x0D0A當成行尾改寫大小差別不大內(nèi)容已經(jīng)錯了。解決二進制文件一律bin文本文件才用ascii按文件類型拆成不同腳本。已經(jīng)傳壞的文件沒法修只能重傳如果對端有歷史備份比對一下大小和校驗和就能確認是哪一批壞的。5.4 現(xiàn)象白天測試都正常下班之后任務就再也不跑了原因任務計劃用了默認的「只在用戶登錄時運行」。測試的時候人坐在機器前會話一直在下班注銷或者機器重啟之后沒人登錄任務就沒有可用的登錄令牌觸發(fā)時直接被跳過。圖形界面里這個選項藏在「常規(guī)」頁頂部向?qū)Ю锔静粫崾?。解決改成「不管用戶是否登錄都運行」并輸入密碼或者把運行賬戶換成SYSTEM。改完之后做一次驗證注銷當前用戶等一個觸發(fā)周期再登錄進來看「上次運行結(jié)果」和日志文件有沒有新內(nèi)容。不注銷就驗證的等于沒驗證。5.5 現(xiàn)象賬號密碼都對就是登錄失敗日志里user那一行被截斷了原因FTP 腳本按空格分詞密碼里帶空格、#、;這類字符時user 用戶名 密碼這一行會被拆成多段客戶端把第二段當成密碼后面的當成未知命令。原料示例里密碼是123456看著沒問題換成真實環(huán)境的復雜密碼就中招。解決最直接的辦法是把密碼改成不含空格和特殊符號的字符串。改不了的話就別把密碼寫死在腳本里改成每次運行前用echo生成一個臨時腳本跑完刪掉——雖然多了幾步但至少不會被分詞坑到。另外把明文密碼放在.ftp文件里本身就有風險文件權限要收緊到只有運行賬戶可讀。6. 從「能跑」到「跑壞了知道」退出碼判斷、日志計數(shù)與過期清理腳本能定時跑起來只是及格線真正省心的是它出問題的時候你能第一時間知道。ftp.exe的退出碼信息量很有限連接失敗返回 2命令執(zhí)行中出錯返回 1 或 0光看退出碼判斷不了「文件到底傳沒傳全」。可行的辦法是回到日志里數(shù)226 Transfer complete出現(xiàn)的次數(shù)和預期文件數(shù)比。下面這段是可以直接用的收尾邏輯echo off setlocal set LOGDIRC:\logs if not exist %LOGDIR% md %LOGDIR% set LOG%LOGDIR%\ftp_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log cd /d C:\datatran ftp -n -v -s:C:\scripts\1.ftp %LOG% 21 rem 統(tǒng)計成功傳輸次數(shù)和預期文件數(shù)比對 set EXPECT12 for /f %%c in (findstr /c:226 Transfer complete %LOG% ^| find /c /v ) do set ACTUAL%%c if not %ACTUAL%%EXPECT% ( echo [%DATE% %TIME%] 傳輸數(shù)不符 預期%EXPECT% 實際%ACTUAL% %LOGDIR%\alert.log exit /b 1 ) rem 清理 7 天前的日志避免目錄無限膨脹 forfiles /p %LOGDIR% /m *.log /d -7 /c cmd /c del path nul 21 exit /b 0關鍵在for /f那一行findstr篩出所有含226 Transfer complete的行管道交給find /c /v 計數(shù)。find /c單獨用會要求輸入文件名配上/v 表示「統(tǒng)計所有不含空串的行」也就是統(tǒng)計全部行這是批處理里數(shù)行數(shù)的老技巧。EXPECT要按實際情況改文件數(shù)每天變的話可以改成和遠端目錄列表比對或者干脆只判斷「實際數(shù)是否大于 0」。forfiles /d -7按修改時間篩出 7 天前的文件/c cmd /c del path逐個刪掉日志目錄就不會越堆越大。還有一個容易被忽略的點%ERRORLEVEL%在setlocal作用域里是即時值但在if塊里引用時如果是延遲展開環(huán)境要用!ERRORLEVEL!。上面的寫法把ftp和判斷拆在兩條獨立語句里避開了這個坑代價是丟掉了ftp的原始退出碼。要兩個都保留的話在ftp那行之后立刻set RC%ERRORLEVEL%再用%RC%判斷。從那以后我每次掛無人值守任務都強制走一遍「手工跑 → 看日志 → 注銷會話再跑一次」這三步一步都不省。省下的那十分鐘往往要用一個通宵來找回來。希望幫到你。本文還有配套的精品資源點擊獲取