国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
InfoQ: 通過(guò)SSH和Ruby實(shí)現(xiàn)自動(dòng)化文件上載

計(jì)算機(jī)技術(shù)就像計(jì)算機(jī)本身一樣飛速發(fā)展,這難道不有趣嗎?一些做硬編碼計(jì)算機(jī)編程的人們?nèi)缃裨谠缙赪eb迷人的時(shí)光里開(kāi)始接觸HTML和CGI。我就是其中之一。如果你也涉獵了叫做“Web設(shè)計(jì)”的偽碼夢(mèng)幻世界的話(huà),你無(wú)疑會(huì)發(fā)現(xiàn)在這個(gè)時(shí)代絕大多數(shù)設(shè)計(jì)師會(huì)分屬于兩個(gè)陣營(yíng)之一。第一陣營(yíng)是采用一個(gè)所見(jiàn)即所得(WYSIWYG)的編輯器比如Dreamweaver來(lái)設(shè)計(jì)和發(fā)布網(wǎng)頁(yè)。第二陣營(yíng)使用諸如Emacs或Vim的文本編輯器來(lái)手工編碼HTML,然后通過(guò)一個(gè)FTP客戶(hù)端將完成的網(wǎng)頁(yè)上傳到一臺(tái)Web服務(wù)器讓世界看見(jiàn)并欣賞它,希望如此。第一陣營(yíng)犧牲靈活性換取便利性,而第二陣營(yíng)正好相反。沒(méi)有哪一種方法是錯(cuò)的,但是也沒(méi)有哪一種是完全正確的。

在我早年的Web設(shè)計(jì)中我屬于第一陣營(yíng)。最近我擁抱了使用寫(xiě)字板的命運(yùn)并加入了那些“手工制作”的隊(duì)伍。我喜歡這樣做所帶來(lái)的靈活性上的收益,但是也付出了損失易用性的代價(jià)。在本地安裝Web服務(wù)器并直接編輯文件不但浪費(fèi)時(shí)間而且不具移植性,所以我通常修改一個(gè)頁(yè)面、轉(zhuǎn)換到FTP客戶(hù)端、上載文件、轉(zhuǎn)換到瀏覽器并刷新以查看上載后的文件。這事做起來(lái)不算快,而且還需要反復(fù)做。這就是一個(gè)高喊著“把我自動(dòng)化”的過(guò)程。所以在上個(gè)夏天,我啟動(dòng)了最喜歡的文本編輯器并決定開(kāi)始動(dòng)手。 

我試圖寫(xiě)一個(gè)程序來(lái)做所有這些我需要手工來(lái)做的事情,但是更快更準(zhǔn)確。我決定使用Ruby來(lái)編寫(xiě)自動(dòng)化腳本。我試圖使代碼短小并具可維護(hù)性,因?yàn)樯院笪疫€要加入一些其他特性。Ruby(作為動(dòng)態(tài)類(lèi)型的語(yǔ)言)讓編寫(xiě)緊湊的代碼變得簡(jiǎn)單,將困擾最小化。它雖是腳本語(yǔ)言,但是也面向?qū)ο?。這使得我可以避免代碼重復(fù),從而比使用過(guò)程語(yǔ)言更為優(yōu)雅。Ruby還擁有一個(gè)相當(dāng)出色的開(kāi)源SFTP庫(kù)可供使用(Net::SFTP[0]),因此我不必自己動(dòng)手編寫(xiě)。(SFTP是一個(gè)安全傳輸文件的網(wǎng)絡(luò)協(xié)議。)

在這篇文章中,我將指導(dǎo)你逐步完成整個(gè)流程,創(chuàng)建這個(gè)程序自己的版本。文章中包含了完整的示例源代碼,并帶有逐行的代碼分析。我邀請(qǐng)你參與進(jìn)來(lái)并體驗(yàn)Ruby是如何能夠輕易的將你的工作自動(dòng)例行化的。

需求

我們的程序有一個(gè)基本需求:它要連接到一臺(tái)遠(yuǎn)程的SFTP服務(wù)器并上載我們的文件。不過(guò)我們也希望它可以做到僅上載那些本地修改過(guò)的文件,并能夠在判斷文件上載的時(shí)候可以遞歸的檢查其子目錄。

腳本預(yù)想的流程應(yīng)該是:

  1. 和遠(yuǎn)程服務(wù)器建立起一個(gè)SFTP連接
  2. 列出本地目錄下所有的文件和子目錄
  3. 比較本地文件的時(shí)間戳和遠(yuǎn)程目錄下文件的時(shí)間戳,僅上載本地修改過(guò)的文件
  4. 遞歸訪(fǎng)問(wèn)所有本地子目錄并重復(fù)步驟2,必要時(shí)創(chuàng)建遠(yuǎn)程子目錄

顯然步驟1到3可以通過(guò)Ruby的內(nèi)建對(duì)象和Net::SFTP輕松搞定。步驟4很有趣。盡管Ruby的Dir類(lèi)提供了一種遞歸訪(fǎng)問(wèn)子目錄的方法,但是和我們需要的還有所不同。既然Ruby對(duì)語(yǔ)言的擴(kuò)展非常簡(jiǎn)單,為什么我們不自己寫(xiě)一個(gè)方法?不僅僅是因?yàn)檫@樣做會(huì)很有趣,而且我們還將學(xué)到擴(kuò)展Ruby是多么的容易。

依賴(lài)

除了Ruby本身以外,我們依賴(lài)的僅僅是Net::SFTP和Net::SSH[1]這兩個(gè)庫(kù)了。幸運(yùn)的是,這兩個(gè)軟件包都是可以通過(guò)Gem[2]來(lái)安裝的。假定你已經(jīng)在本地機(jī)器上安裝了Ruby,并正確設(shè)置了Gem的路徑,然后在命令提示符前輸入:

gem install net-ssh --include-dependencies
gem install net-sftp --include-dependencies

編碼開(kāi)始!


現(xiàn)在我們準(zhǔn)備開(kāi)始寫(xiě)點(diǎn)兒代碼。我們先來(lái)嘗試連接遠(yuǎn)程服務(wù)器、列出一個(gè)給定本地目錄的所有文件并關(guān)閉連接。我們將會(huì)使用Net::SSH和Net::SFTP接口以及Ruby的Dir類(lèi)來(lái)實(shí)現(xiàn)。

1: require 'net/ssh'
2: require 'net/sftp'
3: Net::SSH.start('server', 'username', 'password') do |ssh|
4: ssh.sftp.connect do |sftp|
5: Dir.foreach('.') do |file|
6: puts file
7: end
8: end
9: end

讓我們逐行看一下:

  1. 加載Net::SSH庫(kù)。
  2. 加載Net::SFTP庫(kù),因?yàn)槲覀冞@兩個(gè)庫(kù)都會(huì)用到。
  3. 通過(guò)一個(gè)給定的用戶(hù)名和密碼建立一個(gè)SSH會(huì)話(huà)(諸如代理服務(wù)器之類(lèi)的附加參數(shù)也可以在這里給定。更多信息參見(jiàn)API文檔)。
  4. 打開(kāi)對(duì)遠(yuǎn)程服務(wù)器的SFTP連接。
  5. 用Dir類(lèi)列出當(dāng)前工作目錄的所有文件。
  6. 打印出每個(gè)文件名。
  7. 退出文件列表循環(huán)。
  8. -
  9. 關(guān)閉SFTP和SSH連接。

在我的系統(tǒng)上執(zhí)行了腳本以后,產(chǎn)生的輸出如下:

 .
..
cgi-bin
etc
logs
public_html
temp

回頭看看我們最初的需求列表,我們只用了9行代碼就完成了步驟1和步驟2。
下面來(lái)到步驟3,比較列出文件的時(shí)間戳和其所對(duì)應(yīng)的遠(yuǎn)程時(shí)間戳,僅僅上載那些修改過(guò)的文件。(為了實(shí)現(xiàn)這個(gè)目的,我們定義一個(gè)文件是否修改過(guò)為本地時(shí)間戳大于等于遠(yuǎn)程服務(wù)器上的時(shí)間戳。)使用Ruby比較時(shí)間戳想當(dāng)容易。實(shí)際上,比較本身只用一行代碼就能夠做到。

現(xiàn)在讓我們看看腳本:

1: require 'net/ssh'
2: require 'net/sftp'
3: Net::SSH.start('server', 'username', 'password') do |ssh|
4: ssh.sftp.connect do |sftp|
5: Dir.foreach('.') do |file|
6: next if File.stat(file).directory?
7: begin
8: local_file_changed = File.stat(file).mtime > Time.at(sftp.stat(file).mtime)
9: rescue Net::SFTP::Operations::StatusException
10: not_uploaded = true
11: end
12: if not_uploaded or local_file_changed
13: puts "#{file} has changed and will be uploaded"
14: sftp.put_file(file, file)
15: end
16: end
17: end
18: end

讓我們逐行來(lái)看一下:

1. - 2. 加載Net::SSH和Net::SFTP。
3. - 4. 建立SSH會(huì)話(huà)和SFTP連接。
5. 遍歷當(dāng)前工作目錄下的所有文件。
6. 由于當(dāng)前我們還不能遞歸訪(fǎng)問(wèn)目錄,所以需要查看當(dāng)前文件是否是一個(gè)目錄。如果是的話(huà)則跳過(guò)到循環(huán)的下個(gè)迭代。
7. - 11. 由于遠(yuǎn)程文件可能不存在, 所以我們需要捕捉當(dāng)我們?cè)噲D去查看一個(gè)不存在的文件的時(shí)間戳的時(shí)候Net::SFTP拋出的異常。我們?cè)O(shè)置了兩個(gè)標(biāo)志,一個(gè)用于標(biāo)記本地文件是否修改過(guò)并需要上載,另一個(gè)用于標(biāo)記遠(yuǎn)程文件是否存在。
12. - 13. 如果本地文件沒(méi)有被上載過(guò)或者比遠(yuǎn)程文件要新的話(huà),打印一行文字說(shuō)明文件將被上載。
14. 上載本地文件到遠(yuǎn)程服務(wù)器。
15. - 18. 結(jié)束if語(yǔ)句、文件循環(huán)、SFTP連接和SSH會(huì)話(huà)。

現(xiàn)在我們已經(jīng)完成了三個(gè)需求。我們現(xiàn)在的腳本可以登錄到遠(yuǎn)程服務(wù)器并上載所有本地系統(tǒng)中修改過(guò)的文件,但是腳本還只是僅僅能處理單一目錄。它還不能盡如子目錄去查看需要上載的文件。它也不能創(chuàng)建遠(yuǎn)程服務(wù)器上沒(méi)有的目錄。我們會(huì)在在我們宣布腳本完成以前解決這兩個(gè)問(wèn)題。

遞歸

讓我們完善腳本,實(shí)現(xiàn)遞歸訪(fǎng)問(wèn)子目錄并處理包含需要上載文件的目錄在遠(yuǎn)程服務(wù)器不存在的情況:

1: require 'net/ssh'
2: require 'net/sftp'
3: require 'dir'
4:
5: local_path = 'C:\public_html'
6: remote_path = '/usr/jsmith/public_html'
7: file_perm = 0644
8: dir_perm = 0755
9:
10: puts 'Connecting to remote server'
11: Net::SSH.start('server', 'username', 'password') do |ssh|
12: ssh.sftp.connect do |sftp|
13: puts 'Checking for files which need updating'
14: Find.find(local_path) do |file|
15: next if File.stat(file).directory?
16: local_file = "#{dir}/#{file}"
17: remote_file = remote_path + local_file.sub(local_path, '')
18:
19: begin
20: remote_dir = File.dirname(remote_file)
21: sftp.stat(remote_dir)
22: rescue Net::SFTP::Operations::StatusException => e
23: raise unless e.code == 2
24: sftp.mkdir(remote_dir, :permissions => dir_perm)
25: end
26:
27: begin
28: rstat = sftp.stat(remote_file)
29: rescue Net::SFTP::Operations::StatusException => e
30: raise unless e.code == 2
31: sftp.put_file(local_file, remote_file)
32: sftp.setstat(remote_file, :permissions => file_perm)
33: next
34: end
35:
36: if File.stat(local_file).mtime > Time.at(rstat.mtime)
37: puts "Copying #{local_file} to #{remote_file}"
38: sftp.put_file(local_file, remote_file)
39: end
40: end
41: end
42:
43: puts ‘Disconnecting from remote server'
44: end
45: end
46:
47: puts 'File transfer complete'

哇嗚!這個(gè)要比我們之前的版本長(zhǎng)很多,但這主要是處理遠(yuǎn)程目錄不存在的時(shí)候必須要做的異常檢查造成的。這是Net::SFTP庫(kù)的一個(gè)限制。當(dāng)我們?cè)噲D上載一個(gè)并不存在的遠(yuǎn)程目錄的時(shí)候,put_file方法將會(huì)拋出一個(gè)令人討厭的異常。put_file方法理應(yīng)通過(guò)自動(dòng)創(chuàng)建文件目錄樹(shù)中的缺失部分來(lái)處理這種情況。然而修改這個(gè)方法并不在本文討論的范圍以?xún)?nèi),因此我把這個(gè)留給你作為練習(xí)。

讓我們逐行來(lái)看一下新代碼:

1. - 4. 加載Net::SSH和Net::SFTP。
5. - 6. 定義變量用于設(shè)定將會(huì)被比較和上載的本地和遠(yuǎn)程的目錄。
7. - 8. 定義變量用于設(shè)定當(dāng)遠(yuǎn)程服務(wù)器不存在的時(shí)候我們需要設(shè)定的文件和目錄的默認(rèn)權(quán)限。
9. - 13. 建立到遠(yuǎn)程服務(wù)器的SSH會(huì)話(huà)和SFTP連接。
14. 開(kāi)始遞歸訪(fǎng)問(wèn)每個(gè)子目錄。
15. 循環(huán)當(dāng)前目錄下的每個(gè)條目。
15. 如果當(dāng)前條目是目錄而非文件則跳過(guò)至下一條目。
16. 設(shè)置local_file變量為我們遍歷到的本地文件,相對(duì)于我們的當(dāng)前目錄。
17. 設(shè)置remote_file變量為遠(yuǎn)程服務(wù)器的目標(biāo)路徑,并前綴remote_dir路徑以便我們可以上傳至正確的地址而不是用戶(hù)的home目錄。
19. - 26. 這是另一段惹人厭的代碼,如果Net::SFTP能在文件處理方面再智能些這些代碼就不會(huì)出現(xiàn)在這里。我們需要檢查我們?cè)噲D上載的遠(yuǎn)程目錄是否已經(jīng)存在。為了實(shí)現(xiàn)這個(gè)功能,我們調(diào)用sftp.stat(..)并傳入待檢查的目錄名。如果stat拋出一個(gè)異常且屬性碼是2,則說(shuō)明遠(yuǎn)程目錄不存在。我們則需要?jiǎng)?chuàng)建它并設(shè)置正確的權(quán)限。
27. - 35. 更令人厭惡的代碼,用于檢查即將上載的遠(yuǎn)程文件是否存在。然后其實(shí)我們可以不必做這個(gè)檢查就創(chuàng)建遠(yuǎn)程文件,因?yàn)楫?dāng)我們上載文件的時(shí)候會(huì)自動(dòng)創(chuàng)建。但是我們需要做這個(gè)檢查,因?yàn)楫?dāng)上傳一個(gè)新文件時(shí)我們要給遠(yuǎn)程文件設(shè)置適當(dāng)?shù)臋?quán)限。如果我們不這么做的話(huà)則會(huì)使用默認(rèn)的UNIX權(quán)限,這樣做可能會(huì)禁止我們稍后的文件上載。
36. - 40. 最后,如果到了這里,說(shuō)明將要上載的遠(yuǎn)程目錄和文件都存在。我們比較本地文件和遠(yuǎn)程文件的修改時(shí)間。如果本地文件更新,則上載它。
40. - 48. 所有我們開(kāi)啟的循環(huán)的結(jié)束,關(guān)閉和遠(yuǎn)程服務(wù)器的SFTP連接和SSH會(huì)話(huà)。

這是腳本執(zhí)行的時(shí)候可能產(chǎn)生的輸出:

Connecting to remote server
Checking for files which need updating
Copying D:/html/index.php to /home/public_html/index.php
Copying D:/html/media.php to /home/public_html/media.php
Copying D:/html/contact.php to /home/public_html/contact.php
Copying D:/html/images/go.gif to /home/public_html/images/go.gif
Copying D:/html/images/stop.gif to /home/public_html/images/stop.gif
Copying D:/html/include/menu.php to /home/public_html/include/menu.php
Disconnecting from remote server
File transfer complete

我們成功了!現(xiàn)在我們有了一個(gè)從任意深度的本地目錄樹(shù)上載文件到遠(yuǎn)程服務(wù)器上的快速、方便的方法。腳本相當(dāng)?shù)穆斆?,?dāng)目錄不存在的時(shí)候會(huì)創(chuàng)建目錄,而且只上載那些實(shí)際修改過(guò)的文件。

改進(jìn)的方向

盡管我們開(kāi)發(fā)的“骨架”級(jí)腳本已經(jīng)相當(dāng)有用,但是依然存在一些我們僅通過(guò)少許工作就可以實(shí)現(xiàn)的改進(jìn):

  • 處理本地刪除的文件和目錄。我們當(dāng)前的腳本當(dāng)本地的目錄被刪除的時(shí)候還不能從遠(yuǎn)程服務(wù)器移除。在移除遠(yuǎn)程文件之前可能需要提示用戶(hù)以免重要的文件被誤刪除。
  • 為判斷文件修改增加其他檢查。比較時(shí)間戳的方法的確很好,但是為什么不同時(shí)比較一下文件的大?。慨?dāng)所連接的服務(wù)器并沒(méi)有設(shè)置準(zhǔn)確時(shí)間的時(shí)候這種檢查是很有用的。
  • 記錄上載文件的日志。我增加了打印到標(biāo)準(zhǔn)輸出的語(yǔ)句,但是為什么不采用一個(gè)更加成熟的日志機(jī)制來(lái)記錄文件上載的時(shí)間和地點(diǎn)?(如果你決定每天或每周運(yùn)行腳本的話(huà)這將是很重要的。)
  • 采用Capistrano[4]重寫(xiě)腳本。Jamis Buck用于編寫(xiě)部署腳本的優(yōu)秀框架是一個(gè)理想的選擇,可作為一個(gè)永久解決方案在項(xiàng)目之間使用。

同時(shí),算不得是改進(jìn)的是,Net::SSH庫(kù)支持公鑰認(rèn)證。運(yùn)行PuTTY的Pageant應(yīng)用程序(請(qǐng)看http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html)并添加你的密鑰,然后從我們的腳本的Net::SSH.start語(yǔ)句中移除你的密碼。現(xiàn)在你可以在不將密碼明文儲(chǔ)存的情況下上載文件,也不必每次連接遠(yuǎn)程服務(wù)器的時(shí)候輸入密碼了。真好!

總結(jié)

隨著時(shí)間的推移, 這個(gè)腳本已經(jīng)為我節(jié)省了數(shù)十個(gè)小時(shí),我不再需要手工使用FTP GUI,也不需要通過(guò)一個(gè)惱人的FTP命令行程序頻繁的變換目錄。我希望這個(gè)腳本對(duì)你的工作也起到同樣的作用。如果是這樣的話(huà),我邀請(qǐng)你通過(guò)我的網(wǎng)站(http://www.matthewbass.com/)聯(lián)系我并讓我知曉。我也同樣有興趣聽(tīng)到你對(duì)改進(jìn)此腳本的建議,或者你完成了一個(gè)漂亮的重構(gòu)可以精簡(jiǎn)一到兩行代碼。盡情的使用Ruby吧!

注腳

1. Net::SFTP是一個(gè)基于SFTP安全傳送文件的Ruby API。它是Net::SSH的一部分。

2. Net::SSH是一個(gè)通過(guò)secure shell訪(fǎng)問(wèn)資源的Ruby API。http://rubyforge.org/projects/net-ssh/

3. Gem是Ruby的包管理器。http://www.rubygems.org/

4. 用Ruby實(shí)現(xiàn)自動(dòng)應(yīng)用程序部署。http://manuals.rubyonrails.com/read/book/17

查看英文原文:Automating File Uploads with SSH and Ruby
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Linux下sftp命令傳輸文件的例子
SecureCRT上傳下載數(shù)據(jù)的方法
SSH和SFTP的簡(jiǎn)單使用
sftp命令使用方法
【Linux 命令】scp 命令詳解
070803git用法小結(jié)(1)--建立遠(yuǎn)程倉(cāng)庫(kù)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服