一般命令
創(chuàng)新互聯(lián)公司是一家專注于成都做網站、成都網站設計與策劃設計,殷都網站建設哪家好?創(chuàng)新互聯(lián)公司做網站,專注于網站建設10多年,網設計領域的專業(yè)建站公司;建站業(yè)務涵蓋:殷都等地區(qū)。殷都做網站價格咨詢:18982081108
所謂一般命令,就是在一定時間內會執(zhí)行完的命令。比如 grep, cat 等等。 執(zhí)行命令的步驟是:連接,執(zhí)行,獲取結果
連接
連接包含了認證,可以使用 password 或者 sshkey 2種方式來認證。下面的示例為了簡單,使用了密碼認證的方式來完成連接。
import (
"fmt"
"time"
"golang.org/x/crypto/ssh"
)
func connect(user, password, host string, port int) (*ssh.Session, error) {
var (
auth []ssh.AuthMethod
addr string
clientConfig *ssh.ClientConfig
client *ssh.Client
session *ssh.Session
err error
)
// get auth method
auth = make([]ssh.AuthMethod, 0)
auth = append(auth, ssh.Password(password))
clientConfig = ssh.ClientConfig{
User: user,
Auth: auth,
Timeout: 30 * time.Second,
}
// connet to ssh
addr = fmt.Sprintf("%s:%d", host, port)
if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
return nil, err
}
// create session
if session, err = client.NewSession(); err != nil {
return nil, err
}
return session, nil
}
連接的方法很簡單,只要提供登錄主機的 用戶*, *密碼*, *主機名或者IP*, *SSH端口
執(zhí)行,命令獲取結果
連接成功后,執(zhí)行命令很簡單
import (
"fmt"
"log"
"os"
"time"
"golang.org/x/crypto/ssh"
)
func main() {
session, err := connect("root", "xxxxx", "127.0.0.1", 22)
if err != nil {
log.Fatal(err)
}
defer session.Close()
session.Run("ls /; ls /abc")
}
上面代碼運行之后,雖然命令正常執(zhí)行了,但是沒有正常輸出的結果,也沒有異常輸出的結果。 要想顯示結果,需要將 session 的 Stdout 和 Stderr 重定向 修改 func main 為如下:
func main() {
session, err := connect("root", "xxxxx", "127.0.0.1", 22)
if err != nil {
log.Fatal(err)
}
defer session.Close()
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Run("ls /; ls /abc")
}
這樣就能在屏幕上顯示正常,異常的信息了。
交互式命令
上面的方式無法遠程執(zhí)行交互式命令,比如 top , 遠程編輯一個文件,比如 vi /etc/nginx/nginx.conf 如果要支持交互式的命令,需要當前的terminal來接管遠程的 PTY。
func main() {
session, err := connect("root", "olordjesus", "dockers.iotalabs.io", 2210)
if err != nil {
log.Fatal(err)
}
defer session.Close()
fd := int(os.Stdin.Fd())
oldState, err := terminal.MakeRaw(fd)
if err != nil {
panic(err)
}
defer terminal.Restore(fd, oldState)
// excute command
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
termWidth, termHeight, err := terminal.GetSize(fd)
if err != nil {
panic(err)
}
// Set up terminal modes
modes := ssh.TerminalModes{
ssh.ECHO: 1, // enable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
// Request pseudo terminal
if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil {
log.Fatal(err)
}
session.Run("top")
}
GO是編譯性語言,所以函數(shù)的順序是無關緊要的,為了方便閱讀,建議入口函數(shù) main 寫在最前面,其余函數(shù)按照功能需要進行排列
GO的函數(shù) 不支持嵌套,重載和默認參數(shù)
GO的函數(shù) 支持 無需聲明變量,可變長度,多返回值,匿名,閉包等
GO的函數(shù)用 func 來聲明,且左大括號 { 不能另起一行
一個簡單的示例:
輸出為:
參數(shù):可以傳0個或多個值來供自己用
返回:通過用 return 來進行返回
輸出為:
上面就是一個典型的多參數(shù)傳遞與多返回值
對例子的說明:
按值傳遞:是對某個變量進行復制,不能更改原變量的值
引用傳遞:相當于按指針傳遞,可以同時改變原來的值,并且消耗的內存會更少,只有4或8個字節(jié)的消耗
在上例中,返回值 (d int, e int, f int) { 是進行了命名,如果不想命名可以寫成 (int,int,int){ ,返回的結果都是一樣的,但要注意:
當返回了多個值,我們某些變量不想要,或實際用不到,我們可以使用 _ 來補位,例如上例的返回我們可以寫成 d,_,f := test(a,b,c) ,我們不想要中間的返回值,可以以這種形式來舍棄掉
在參數(shù)后面以 變量 ... type 這種形式的,我們就要以判斷出這是一個可變長度的參數(shù)
輸出為:
在上例中, strs ...string 中, strs 的實際值是b,c,d,e,這就是一個最簡單的傳遞可變長度的參數(shù)的例子,更多一些演變的形式,都非常類似
在GO中 defer 關鍵字非常重要,相當于面相對像中的析構函數(shù),也就是在某個函數(shù)執(zhí)行完成后,GO會自動這個;
如果在多層循環(huán)中函數(shù)里,都定義了 defer ,那么它的執(zhí)行順序是先進后出;
當某個函數(shù)出現(xiàn)嚴重錯誤時, defer 也會被調用
輸出為
這是一個最簡單的測試了,當然還有更復雜的調用,比如調試程序時,判斷是哪個函數(shù)出了問題,完全可以根據(jù) defer 打印出來的內容來進行判斷,非??焖?,這種留給你們去實現(xiàn)
一個函數(shù)在函數(shù)體內自己調用自己我們稱之為遞歸函數(shù),在做遞歸調用時,經常會將內存給占滿,這是非常要注意的,常用的比如,快速排序就是用的遞歸調用
本篇重點介紹了GO函數(shù)(func)的聲明與使用,下一篇將介紹GO的結構 struct
Transact-SQL 參考
GO
用信號通知 Microsoft? SQL Server? 實用工具一批 Transact-SQL 語句的結束。
語法
GO
注釋
GO 不是 Transact-SQL 語句;而是可為 osql 和 isql 實用工具及 SQL Server 查詢分析器識別的命令。
SQL Server 實用工具將 GO 解釋為應將當前的 Transact-SQL 批處理語句發(fā)送給 SQL Server 的信號。當前批處理語句是自上一 GO 命令后輸入的所有語句,若是第一條 GO 命令,則是從特殊會話或腳本的開始處到這條 GO 命令之間的所有語句。SQL 查詢分析器和 osql 及 isql 命令提示實用工具執(zhí)行 GO 命令的方式不同。有關更多信息,請參見 osql 實用工具、isql 實用工具和 SQL 查詢分析器。
GO 命令和Transact-SQL 語句不可在同一行上。但在 GO 命令行中可包含注釋。
用戶必須遵照使用批處理的規(guī)則。例如,在批處理中的第一條語句后執(zhí)行任何存儲過程必須包含 EXECUTE 關鍵字。局部(用戶定義)變量的作用域限制在一個批處理中,不可在 GO 命令后引用。
USE pubs
GO
DECLARE @MyMsg VARCHAR(50)
SELECT @MyMsg = 'Hello, World.'
GO -- @MyMsg is not valid after this GO ends the batch.
-- Yields an error because @MyMsg not declared in this batch.
PRINT @MyMsg
GO
SELECT @@VERSION;
-- Yields an error: Must be EXEC sp_who if not first statement in
-- batch.
sp_who
GO
SQL Server 應用程序可將多條 Transact-SQL 語句作為一個批處理發(fā)給 SQL Server 去執(zhí)行。在此批處理中的語句編譯成一個執(zhí)行計劃。程序員在 SQL Server 實用工具中執(zhí)行特定語句,或生成 Transact-SQL 語句腳本在 SQL Server 實用工具中運行,用 GO 來標識批處理的結束。
如果基于 DB-Library、ODBC 或 OLE DB APIs 的應用程序試圖執(zhí)行 GO 命令時會收到語法錯誤。SQL Server 實用工具永遠不會向服務器發(fā)送 GO 命令。
權限
GO 是一個不需權限的實用工具命令??梢杂扇魏斡脩魣?zhí)行。
示例
下面的示例創(chuàng)建兩個批處理。第一個批處理只包含一條 USE pubs 語句,用于設置數(shù)據(jù)庫上下文。剩下的語句使用了一個局部變量,因此所有的局部變量聲明必須在一個批處理中。這一點可通過在最后一條引用此變量的語句之后才使用 GO 命令來做到。
USE pubs
GO
DECLARE @NmbrAuthors int
SELECT @NmbrAuthors = COUNT(*)
FROM authors
PRINT 'The number of authors as of ' +
CAST(GETDATE() AS char(20)) + ' is ' +
CAST(@NmbrAuthors AS char (10))
GO
在以下這段代碼中,我們操作一個文件,無論成功與否都需要關閉文件句柄。這里在三處不同的位置都調用了file.Close()方法,代碼顯得非常冗余。
我們利用延遲調用來優(yōu)化代碼。定義后的defer代碼,會在return之前返回,讓代碼顯得更加緊湊,且可讀性變強,對上面的代碼改造如下:
我們通過這個示例來看一下延遲調用與正常代碼之間的執(zhí)行順序
先簡單分析一下代碼邏輯:
從輸出中,我們可以觀察到如下現(xiàn)象:
從這個實例中,我們很明顯觀察到,defer語句是在return之前執(zhí)行
如果一個函數(shù)內定義了多個defer,則調用順序為LIFO(后進先出)方式執(zhí)行。
仍然是相同的例子,但是在TestDefer中我們定義了三個defer輸出,根據(jù)LIFO原則,輸出的順序是3rd-2nd-1st,根據(jù)最后的結果,也是逆向向上執(zhí)行defer輸出。
就在整理這篇筆記的時候,發(fā)現(xiàn)了自己的認知誤區(qū),主要是本節(jié)實例三中發(fā)現(xiàn)的,先來看一下英文的描述:
對于上面的這段話的理解:
下面是代碼執(zhí)行輸出,我們來一起分析一下:
雖然在a()函數(shù)內,顯示的返回了10,但是main函數(shù)中得到的結果是defer函數(shù)自增后的結果,我們來分析一下代碼:
在這篇文章的上一版,我曾經嘗試用指針取解釋defer修改返回值的類型,但是感覺不夠透徹,也讓閱讀者非常困惑,索性參考了一下go官方blog中的一篇文章,在此基礎上進行了擴展。如需要閱讀原文,可以參考下面的文章。
如下的例子,要打印100以內能被5整除的數(shù),以panic的方式選擇出來并打印。
如果用下面的方式,執(zhí)行到第一個panic就會跳出for循環(huán)
只能輸出第一個匹配項,然后退出for循環(huán)。
那么如何保證在for循環(huán)處理完panic不退出循環(huán),直到打印完所有滿足條件的數(shù)值?
golang的panic被恢復后,能繼續(xù)執(zhí)行比recover更早的defer,或者返回到recover函數(shù)的調用方,然后繼續(xù)執(zhí)行下去。
所以,我們可以把panic和recover放到單獨的函數(shù)中,然后在for循環(huán)里調用這個函數(shù),這個函數(shù)panic并恢復后,能返回到調用方for循環(huán)并繼續(xù)循環(huán)下去。
執(zhí)行結果是所有0到100的所有符合panic條件的都能正確處理,for循環(huán)沒有異常退出:
golang的panic屬于非常嚴重的錯誤,一旦panic沒有recover的話,程序就退出了。一般避免主動panic,影響程序穩(wěn)定性。
recover函數(shù)要放在defer里面,并且只能恢復同一個goroutine的并且是直接調用鏈函數(shù)發(fā)生的panic。recover不能恢復上一層函數(shù)的panic。
本文介紹一些Go語言的基礎語法。
先來看一個簡單的go語言代碼:
go語言的注釋方法:
代碼執(zhí)行結果:
下面來進一步介紹go的基礎語法。
go語言中格式化輸出可以使用 fmt 和 log 這兩個標準庫,
常用方法:
示例代碼:
執(zhí)行結果:
更多格式化方法可以訪問中的fmt包。
log包實現(xiàn)了簡單的日志服務,也提供了一些格式化輸出的方法。
執(zhí)行結果:
下面來介紹一下go的數(shù)據(jù)類型
下表列出了go語言的數(shù)據(jù)類型:
int、float、bool、string、數(shù)組和struct屬于值類型,這些類型的變量直接指向存在內存中的值;slice、map、chan、pointer等是引用類型,存儲的是一個地址,這個地址存儲最終的值。
常量是在程序編譯時就確定下來的值,程序運行時無法改變。
執(zhí)行結果:
執(zhí)行結果:
Go 語言的運算符主要包括算術運算符、關系運算符、邏輯運算符、位運算符、賦值運算符以及指針相關運算符。
算術運算符:
關系運算符:
邏輯運算符:
位運算符:
賦值運算符:
指針相關運算符:
下面介紹一下go語言中的if語句和switch語句。另外還有一種控制語句叫select語句,通常與通道聯(lián)用,這里不做介紹。
if語法格式如下:
if ... else :
else if:
示例代碼:
語法格式:
另外,添加 fallthrough 會強制執(zhí)行后面的 case 語句,不管下一條case語句是否為true。
示例代碼:
執(zhí)行結果:
下面介紹幾種循環(huán)語句:
執(zhí)行結果:
執(zhí)行結果:
也可以通過標記退出循環(huán):
--THE END--