diff --git a/README.md b/README.md
index 4e5845a..6739c75 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,10 @@
## Example
### 在远程执行ssh命令
+提供3个方法: Run() Exec() Output()
+1. Run() : 程序执行后,不再受执行者控制. 适用于启动服务端进程.
+2. Exec() : 在控制台同步实时输出程序的执行结果.
+3. Output() : 会等待程序执行完成后,输出执行结果,在需要对执行的结果进行操作时使用.
```go
package main
import (
@@ -32,7 +36,7 @@ func main() {
}
defer c.Close()
- output, err := c.Exec("uptime")
+ output, err := c.Output("uptime")
if err != nil {
panic(err)
}
diff --git a/client.go b/client.go
index bb26658..e63b1c5 100644
--- a/client.go
+++ b/client.go
@@ -17,6 +17,7 @@ const DefaultTimeout = 30 * time.Second
type Client struct {
*Config
SSHClient *ssh.Client
+ SSHSession *ssh.Session
SFTPClient *sftp.Client
}
@@ -65,7 +66,13 @@ func New(cnf *Config) (client *Client, err error) {
return client, errors.New("Failed to conn sftp: " + err.Error())
}
- return &Client{SSHClient: sshClient, SFTPClient: sftpClient}, nil
+ session, err := sshClient.NewSession()
+ if err != nil {
+ return nil, err
+ }
+ // defer session.Close()
+
+ return &Client{SSHClient: sshClient, SFTPClient: sftpClient, SSHSession: session}, nil
}
// NewClient 根据配置
@@ -149,4 +156,5 @@ func NewWithPrivateKey(Host, Port, User, Passphrase string) (client *Client, err
func (c *Client) Close() {
c.SFTPClient.Close()
c.SSHClient.Close()
+ c.SSHSession.Close()
}
diff --git a/example/bash/Makefile b/example/bash/Makefile
new file mode 100644
index 0000000..b150f08
--- /dev/null
+++ b/example/bash/Makefile
@@ -0,0 +1,124 @@
+PROJECT = transfer
+VERSION = $(shell git describe)
+BRANCH = $(shell git name-rev --name-only HEAD)
+VERSION ="$(echo $TRAVIS_TAG)"
+ARCNAME = $(PROJECT)-$(VERSION)-$(GOOS)-$(GOARCH)
+ARTIFACTS_DIR=artifact
+
+
+# ZIP="zip -9 -r"
+# TAR="tar cvf"
+# GZIP="gzip -9"
+# GZIP_7Z="7za a -tgzip -mx9"
+# ZIP_7Z="7za a -tzip -mx9"
+ifndef ZIP
+ ifneq ($(shell which zip 2>/dev/null),)
+ ZIP := zip -9
+ endif
+ ifneq ($(shell which 7z 2>/dev/null),)
+ ZIP := 7z a -tzip -mx=9
+ endif
+ ifneq ($(shell which 7za 2>/dev/null),)
+ ZIP := 7za a -tzip -mx=9
+ endif
+ ifndef ZIP
+ $(warning "No zip / 7z / 7za in ($(PATH))")
+ ZIP := : zip_not_found
+ endif
+endif
+
+.PHONY: all release release-all
+all: release-all
+
+
+.PHONY: windows-dependencies
+windows-dependencies:
+ @ go get github.com/josephspurrier/goversioninfo/cmd/goversioninfo
+
+.PHONY: embed-assets
+embed-assets:
+ @ GO111MODULE=off go get -u github.com/jteeuwen/go-bindata/...
+ @# go-bindata ./logos/microBadger_headert.png ./webpage.html
+
+
+
+release:
+ env CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) go build $(FLAGS) -ldflags='-s -w -X github.com/rinetd/transfer/version.Version=$(VERSION)' -o build/$(GOOS)-$(GOARCH)/$(PROJECT)$(EXT)
+ - tar czf build/$(ARCNAME).tar.gz -C build/$(GOOS)-$(GOARCH)/ $(PROJECT)$(EXT)
+ - tar czf build/$(ARCNAME).tar.gz -C build/$(GOOS)-$(GOARCH)/ $(PROJECT)$(EXT)
+ifeq ($(OS),Windows_NT)
+ cd dist; \
+ rm -f $(ARCNAME)-*-Win.zip; \
+ $(ZIP) $(ARCNAME)-$(VERSTR)-Win.zip build/$(GOOS)-$(GOARCH)/ $(PROJECT)$(EXT);
+ $(ZIP) dist/$(ARCNAME)-$(VERSTR)-Win.zip -r0 images/*.png;
+endif
+
+release-all:
+ # -@$(MAKE) release GOOS=darwin GOARCH=amd64
+ # -@$(MAKE) release GOOS=linux GOARCH=386
+ # -@$(MAKE) release GOOS=linux GOARCH=amd64
+ -@$(MAKE) release GOOS=windows GOARCH=386 EXT=.exe
+ # -@$(MAKE) release GOOS=windows GOARCH=amd64 EXT=.exe
+
+.PHONY: windows
+windows: windows-dependencies embed-assets
+ goversioninfo -icon=rc/icon.ico -manifest=rc/manifest.exe.manifest rc/versioninfo.json
+ @- rm binaries/*.exe
+ CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -x -ldflags="-s -w " -o binaries/deploy`date +%m%d`.exe
+ @# - rm binaries/deploy_windows_64bit.exe
+ @# - CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w -H=windowsgui -linkmode internal" -o binaries/deploy_windows_64bit.exe
+ rm resource.syso
+
+platform:
+ # @$(MAKE) releaseGOOS=js GOARCH=wasm
+ # @$(MAKE) release GOOS=windows GOARCH=386 FLAGS='-ldflags="-H=windowsgui"' EXE=.exe
+ # @$(MAKE) release GOOS=windows GOARCH=amd64 FLAGS='-ldflags="-H=windowsgui"' EXE=.exe
+ # @$(MAKE) release GOOS=linux GOARCH=arm
+ # @$(MAKE) release GOOS=linux GOARCH=arm64
+ # @$(MAKE) release GOOS=linux GOARCH=mips
+ # @$(MAKE) release GOOS=linux GOARCH=mips64
+ # @$(MAKE) release GOOS=linux GOARCH=mips64le
+ # @$(MAKE) release GOOS=linux GOARCH=mipsle
+ # @$(MAKE) release GOOS=linux GOARCH=ppc64
+ # @$(MAKE) release GOOS=linux GOARCH=ppc64le
+ # @$(MAKE) release GOOS=linux GOARCH=s390x
+ # @$(MAKE) release GOOS=android GOARCH=386
+ # @$(MAKE) release GOOS=android GOARCH=amd64
+ # @$(MAKE) release GOOS=android GOARCH=arm
+ # @$(MAKE) release GOOS=android GOARCH=arm64
+ # @$(MAKE) release GOOS=darwin GOARCH=386
+ # @$(MAKE) release GOOS=darwin GOARCH=arm
+ # @$(MAKE) release GOOS=darwin GOARCH=arm64
+ # @$(MAKE) release GOOS=dragonfly GOARCH=amd64
+ # @$(MAKE) release GOOS=freebsd GOARCH=386
+ # @$(MAKE) release GOOS=freebsd GOARCH=amd64
+ # @$(MAKE) release GOOS=freebsd GOARCH=arm
+ # @$(MAKE) release GOOS=nacl GOARCH=386
+ # @$(MAKE) release GOOS=nacl GOARCH=amd64p32
+ # @$(MAKE) release GOOS=nacl GOARCH=arm
+ # @$(MAKE) release GOOS=netbsd GOARCH=386
+ # @$(MAKE) release GOOS=netbsd GOARCH=amd64
+ # @$(MAKE) release GOOS=netbsd GOARCH=arm
+ # @$(MAKE) release GOOS=openbsd GOARCH=386
+ # @$(MAKE) release GOOS=openbsd GOARCH=amd64
+ # @$(MAKE) release GOOS=openbsd GOARCH=arm
+ # @$(MAKE) release GOOS=plan9 GOARCH=386
+ # @$(MAKE) release GOOS=plan9 GOARCH=amd64
+ # @$(MAKE) release GOOS=plan9 GOARCH=arm
+ # @$(MAKE) release GOOS=solaris GOARCH=amd64
+
+
+.PHONY: build
+build:
+ go get ./...
+
+.PHONY: test
+test:
+ go get -t ./...
+ go test -v ...
+
+build-image:
+ docker build -t rientd/transfer .
+
+clean:
+ rm -rf build dist
diff --git a/example/get/main.go b/example/download/main.go
similarity index 100%
rename from example/get/main.go
rename to example/download/main.go
diff --git a/example/getdata/Makefile b/example/getdata/Makefile
new file mode 100644
index 0000000..396bac3
--- /dev/null
+++ b/example/getdata/Makefile
@@ -0,0 +1,52 @@
+COMPILE_TIME = $(shell date +"%Y-%M-%d %H:%M:%S")
+BUILD=`date +%FT%T%z`
+
+# Setup the -ldflags option for go build here, interpolate the variable values
+LDFLAGS_f1=-ldflags "-w -s -X main.Version=${VERSION} -X main.Build=${BUILD} -X main.Entry=f1"
+LDFLAGS_f2=-ldflags "-w -s -X main.Version=${VERSION} -X main.Build=${BUILD} -X main.Entry=f2"
+
+
+name:=getdata
+# make ver=release
+ifeq ($(ver), debug)
+ CXXFLAGS = -c -g -Ddebug
+else
+ CXXFLAGS = -c -O3
+endif
+
+.PHONY: all
+all: windows
+
+.PHONY: windows-dependencies
+windows-dependencies:
+ go get github.com/josephspurrier/goversioninfo/cmd/goversioninfo
+
+.PHONY: embed-assets
+embed-assets:
+ @# go get github.com/jteeuwen/go-bindata/...
+ @# go-bindata ./logos/$(name)_headert.png ./webpage.html
+
+.PHONY: linux
+linux: *.go embed-assets
+ GOOS=linux GOARCH=amd64 go build -o output/$(name)_linux_64bit
+ GOOS=linux GOARCH=386 go build -o output/$(name)_linux_32bit
+ strip output/$(name)_linux_*
+
+.PHONY: windows
+windows: *.go windows-dependencies embed-assets
+ goversioninfo -icon=rc/icon.ico -manifest=rc/manifest.exe.manifest rc/versioninfo.json
+ @- rm output/*.exe
+ CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags="-s -w " -o output/$(name)_`date +%m-%d`.exe
+ @# - rm output/$(name)_windows_64bit.exe
+ @# - CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w -H=windowsgui -linkmode internal" -o output/deploy_windows_64bit.exe
+ rm resource.syso
+
+.PHONY: osx
+osx: *.go embed-assets
+ GOOS=darwin GOARCH=amd64 go build -o output/$(name)_osx_64bit
+ GOOS=darwin GOARCH=386 go build -o output/$(name)_osx_32bit
+
+
+.PHONY: clean
+clean:
+ rm -rf output/*
\ No newline at end of file
diff --git a/example/getdata/main.go b/example/getdata/main.go
new file mode 100644
index 0000000..917f937
--- /dev/null
+++ b/example/getdata/main.go
@@ -0,0 +1,105 @@
+package getdata
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "path"
+ "time"
+
+ "github.com/pkg/sftp"
+ "golang.org/x/crypto/ssh"
+)
+
+func connect(user, password, host string, port int) (*sftp.Client, error) {
+ var (
+ auth []ssh.AuthMethod
+ addr string
+ clientConfig *ssh.ClientConfig
+ sshClient *ssh.Client
+ sftpClient *sftp.Client
+ 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,
+ HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+ }
+
+ // connet to ssh
+ addr = fmt.Sprintf("%s:%d", host, port)
+
+ if sshClient, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
+ return nil, err
+ }
+
+ // create sftp client
+ if sftpClient, err = sftp.NewClient(sshClient); err != nil {
+ return nil, err
+ }
+
+ return sftpClient, nil
+}
+
+var FORMAT = "2006-01-02"
+var (
+ err error
+ sftpClient *sftp.Client
+)
+var dbnames = []string{"tower", "mengyin", "pingyi", "shizhi", "tancheng", "yinan", "yishui", "feixian", "gaoxinqu", "hedong", "jingkaiqu", "junan", "luozhuang", "lanling", "lanshan", "lingang", "linshu"}
+
+func main() {
+
+ // 这里换成实际的 SSH 连接的 用户名,密码,主机名或IP,SSH端口
+ // sftpClient, err = connect("root", "sdlylshl871016", "111.235.181.127", 443)
+ sftpClient, err = connect("root", "HR2018!!", "15.14.12.150", 22)
+ if err != nil {
+ log.Println(err)
+ }
+ defer sftpClient.Close()
+ // 用来测试的远程文件路径 和 本地文件夹
+ // fmt.Println(shizhi)
+ // var localDir = "."
+ date_dir := "db_" + time.Now().Format(FORMAT)
+ os.Mkdir(date_dir, 0755)
+ var lzkpbi = "/docker/backup/" + time.Now().Format(FORMAT) + "_lzkp_bi_inner.zip"
+ Down(lzkpbi, date_dir)
+ for _, n := range dbnames {
+ p := "/docker/backup/" + time.Now().Format(FORMAT) + "_" + n + "_inner.zip"
+ // fmt.Println(p)
+
+ Down(p, date_dir)
+ }
+ // fmt.Scanln()
+}
+
+func Down(src, dst string) {
+ fmt.Println(src, "数据正在复制中,请耐心等待...")
+ srcFile, err := sftpClient.Open(src)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ defer srcFile.Close()
+
+ var localFileName = path.Base(src)
+ dstFile, err := os.Create(path.Join(dst, localFileName))
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ defer dstFile.Close()
+
+ if _, err = srcFile.WriteTo(dstFile); err != nil {
+ log.Println(err)
+ return
+ }
+
+ fmt.Println(src, "数据复制完成!")
+
+}
diff --git a/example/getdata/rc/icon.ico b/example/getdata/rc/icon.ico
new file mode 100644
index 0000000..94e9663
Binary files /dev/null and b/example/getdata/rc/icon.ico differ
diff --git a/example/getdata/rc/manifest.exe.manifest b/example/getdata/rc/manifest.exe.manifest
new file mode 100644
index 0000000..df4430f
--- /dev/null
+++ b/example/getdata/rc/manifest.exe.manifest
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/getdata/rc/versioninfo.json b/example/getdata/rc/versioninfo.json
new file mode 100644
index 0000000..77423aa
--- /dev/null
+++ b/example/getdata/rc/versioninfo.json
@@ -0,0 +1,43 @@
+{
+ "_FixedFileInfo": {
+ "FileVersion": {
+ "Major": 18,
+ "Minor": 7,
+ "Patch": 16,
+ "Build": 0
+ },
+ "ProductVersion": {
+ "Major": 2018,
+ "Minor": 7,
+ "Patch": 16,
+ "Build": 0
+ },
+ "FileFlagsMask": "3f",
+ "FileFlags ": "00",
+ "FileOS": "040004",
+ "FileType": "01",
+ "FileSubType": "00"
+ },
+ "StringFileInfo": {
+ "FileDescription": "履职考评系统升级",
+ "FileVersion": "2.1.0",
+ "ProductName": "履职考评系统",
+ "ProductVersion": "2018.7.1",
+ "LegalCopyright": "Copyright@pytool",
+ "OriginalFilename": "update.exe",
+ "Comments": " ",
+ "CompanyName": "Company",
+ "InternalName": "",
+ "LegalTrademarks": "",
+ "PrivateBuild": "",
+ "SpecialBuild": ""
+ },
+ "VarFileInfo": {
+ "Translation": {
+ "LangID": "0409",
+ "CharsetID": "04B0"
+ }
+ },
+ "IconPath": "deploy.ico",
+ "ManifestPath": ""
+}
\ No newline at end of file
diff --git a/example/runetl/Makefile b/example/runetl/Makefile
new file mode 100644
index 0000000..bc56960
--- /dev/null
+++ b/example/runetl/Makefile
@@ -0,0 +1,126 @@
+PROJECT = 数据同步
+VERSION = $(shell git describe)
+BRANCH = $(shell git name-rev --name-only HEAD)
+VERSION ="$(echo $TRAVIS_TAG)"
+ARCNAME = $(PROJECT)-$(VERSION)-$(GOOS)-$(GOARCH)
+ARTIFACTS_DIR=artifact
+
+
+# ZIP="zip -9 -r"
+# TAR="tar cvf"
+# GZIP="gzip -9"
+# GZIP_7Z="7za a -tgzip -mx9"
+# ZIP_7Z="7za a -tzip -mx9"
+ifndef ZIP
+ ifneq ($(shell which zip 2>/dev/null),)
+ ZIP := zip -9
+ endif
+ ifneq ($(shell which 7z 2>/dev/null),)
+ ZIP := 7z a -tzip -mx=9
+ endif
+ ifneq ($(shell which 7za 2>/dev/null),)
+ ZIP := 7za a -tzip -mx=9
+ endif
+ ifndef ZIP
+ $(warning "No zip / 7z / 7za in ($(PATH))")
+ ZIP := : zip_not_found
+ endif
+endif
+
+.PHONY: all release release-all
+all: release-all
+
+
+.PHONY: windows-dependencies
+windows-dependencies:
+ @ go get github.com/josephspurrier/goversioninfo/cmd/goversioninfo
+
+.PHONY: embed-assets
+embed-assets:
+ @ GO111MODULE=off go get -u github.com/jteeuwen/go-bindata/...
+ @# go-bindata ./logos/microBadger_headert.png ./webpage.html
+
+
+
+release:
+ goversioninfo -icon=rc/icon.ico -manifest=rc/manifest.exe.manifest rc/versioninfo.json
+ env CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) go build $(FLAGS) -ldflags='-s -w -X github.com/rinetd/transfer/version.Version=$(VERSION)' -o build/$(GOOS)-$(GOARCH)/$(PROJECT)$(EXT)
+ rm resource.syso
+ - tar czf build/$(ARCNAME).tar.gz -C build/$(GOOS)-$(GOARCH)/ $(PROJECT)$(EXT)
+ - tar czf build/$(ARCNAME).tar.gz -C build/$(GOOS)-$(GOARCH)/ $(PROJECT)$(EXT)
+ifeq ($(OS),Windows_NT)
+ cd dist; \
+ rm -f $(ARCNAME)-*-Win.zip; \
+ $(ZIP) $(ARCNAME)-$(VERSTR)-Win.zip build/$(GOOS)-$(GOARCH)/ $(PROJECT)$(EXT);
+ $(ZIP) dist/$(ARCNAME)-$(VERSTR)-Win.zip -r0 images/*.png;
+endif
+
+release-all:
+ # -@$(MAKE) release GOOS=darwin GOARCH=amd64
+ # -@$(MAKE) release GOOS=linux GOARCH=386
+ # -@$(MAKE) release GOOS=linux GOARCH=amd64
+ -@$(MAKE) release GOOS=windows GOARCH=386 EXT=.exe
+ # -@$(MAKE) release GOOS=windows GOARCH=amd64 EXT=.exe
+
+.PHONY: windows
+windows: windows-dependencies embed-assets
+ goversioninfo -icon=rc/icon.ico -manifest=rc/manifest.exe.manifest rc/versioninfo.json
+ @- rm binaries/*.exe
+ CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -x -ldflags="-s -w " -o binaries/deploy`date +%m%d`.exe
+ @# - rm binaries/deploy_windows_64bit.exe
+ @# - CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w -H=windowsgui -linkmode internal" -o binaries/deploy_windows_64bit.exe
+ rm resource.syso
+
+platform:
+ # @$(MAKE) releaseGOOS=js GOARCH=wasm
+ # @$(MAKE) release GOOS=windows GOARCH=386 FLAGS='-ldflags="-H=windowsgui"' EXE=.exe
+ # @$(MAKE) release GOOS=windows GOARCH=amd64 FLAGS='-ldflags="-H=windowsgui"' EXE=.exe
+ # @$(MAKE) release GOOS=linux GOARCH=arm
+ # @$(MAKE) release GOOS=linux GOARCH=arm64
+ # @$(MAKE) release GOOS=linux GOARCH=mips
+ # @$(MAKE) release GOOS=linux GOARCH=mips64
+ # @$(MAKE) release GOOS=linux GOARCH=mips64le
+ # @$(MAKE) release GOOS=linux GOARCH=mipsle
+ # @$(MAKE) release GOOS=linux GOARCH=ppc64
+ # @$(MAKE) release GOOS=linux GOARCH=ppc64le
+ # @$(MAKE) release GOOS=linux GOARCH=s390x
+ # @$(MAKE) release GOOS=android GOARCH=386
+ # @$(MAKE) release GOOS=android GOARCH=amd64
+ # @$(MAKE) release GOOS=android GOARCH=arm
+ # @$(MAKE) release GOOS=android GOARCH=arm64
+ # @$(MAKE) release GOOS=darwin GOARCH=386
+ # @$(MAKE) release GOOS=darwin GOARCH=arm
+ # @$(MAKE) release GOOS=darwin GOARCH=arm64
+ # @$(MAKE) release GOOS=dragonfly GOARCH=amd64
+ # @$(MAKE) release GOOS=freebsd GOARCH=386
+ # @$(MAKE) release GOOS=freebsd GOARCH=amd64
+ # @$(MAKE) release GOOS=freebsd GOARCH=arm
+ # @$(MAKE) release GOOS=nacl GOARCH=386
+ # @$(MAKE) release GOOS=nacl GOARCH=amd64p32
+ # @$(MAKE) release GOOS=nacl GOARCH=arm
+ # @$(MAKE) release GOOS=netbsd GOARCH=386
+ # @$(MAKE) release GOOS=netbsd GOARCH=amd64
+ # @$(MAKE) release GOOS=netbsd GOARCH=arm
+ # @$(MAKE) release GOOS=openbsd GOARCH=386
+ # @$(MAKE) release GOOS=openbsd GOARCH=amd64
+ # @$(MAKE) release GOOS=openbsd GOARCH=arm
+ # @$(MAKE) release GOOS=plan9 GOARCH=386
+ # @$(MAKE) release GOOS=plan9 GOARCH=amd64
+ # @$(MAKE) release GOOS=plan9 GOARCH=arm
+ # @$(MAKE) release GOOS=solaris GOARCH=amd64
+
+
+.PHONY: build
+build:
+ go get ./...
+
+.PHONY: test
+test:
+ go get -t ./...
+ go test -v ...
+
+build-image:
+ docker build -t rientd/transfer .
+
+clean:
+ rm -rf build dist
diff --git a/example/runetl/main.go b/example/runetl/main.go
new file mode 100644
index 0000000..37fb721
--- /dev/null
+++ b/example/runetl/main.go
@@ -0,0 +1,31 @@
+package main
+
+import (
+ "fmt"
+
+ "github.com/pytool/ssh"
+)
+
+func main() {
+ config := ssh.Default.WithHost("192.168.5.157").WithPassword("HR2018!!")
+ // config.Host = "15.14.12.153"
+ client, err := ssh.New(config)
+ // client, err := ssh.NewClient("localhost", "22", "root", "ubuntu")
+ if err != nil {
+ // panic(err)
+ fmt.Println("连接失败,按Enter键退出!")
+ fmt.Scanln()
+ }
+ defer client.Close()
+
+ err = client.Exec("sh /root/shetl/etl.sh")
+ if err != nil {
+ fmt.Println(err)
+ // panic(err)
+ fmt.Println("执行失败,按Enter键退出!")
+ fmt.Scanln()
+ }
+
+ // fmt.Printf("Uptime: %s\n", output)
+
+}
diff --git a/example/runetl/rc/icon.ico b/example/runetl/rc/icon.ico
new file mode 100644
index 0000000..3ba71ab
Binary files /dev/null and b/example/runetl/rc/icon.ico differ
diff --git a/example/runetl/rc/manifest.exe.manifest b/example/runetl/rc/manifest.exe.manifest
new file mode 100644
index 0000000..c7b0c6d
--- /dev/null
+++ b/example/runetl/rc/manifest.exe.manifest
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/runetl/rc/versioninfo.json b/example/runetl/rc/versioninfo.json
new file mode 100644
index 0000000..93b3b9a
--- /dev/null
+++ b/example/runetl/rc/versioninfo.json
@@ -0,0 +1,37 @@
+{
+ "FixedFileInfo": {
+ "FileVersion": {
+ "Major": 1,
+ "Minor": 2,
+ "Patch": 0,
+ "Build": 1
+ },
+ "FileFlagsMask": "3f",
+ "FileFlags ": "00",
+ "FileOS": "040004",
+ "FileType": "01",
+ "FileSubType": "00"
+ },
+ "StringFileInfo": {
+ "Comments": "执行etl",
+ "CompanyName": "pytool",
+ "FileVersion": "",
+ "FileDescription": "执行数据同步etl",
+ "ProductName": "履职考评数据同步",
+ "ProductVersion": "2018.12.11",
+ "LegalCopyright": "Copyright@pytool",
+ "OriginalFilename": "etl.exe",
+ "InternalName": "",
+ "LegalTrademarks": "",
+ "PrivateBuild": "",
+ "SpecialBuild": ""
+ },
+ "VarFileInfo": {
+ "Translation": {
+ "LangID": "0409",
+ "CharsetID": "04B0"
+ }
+ },
+ "IconPath": "icon.ico",
+ "ManifestPath": ""
+}
\ No newline at end of file
diff --git a/cmd/main.go b/example/update/main.go
similarity index 100%
rename from cmd/main.go
rename to example/update/main.go
diff --git a/example/put/main.go b/example/upload/main.go
similarity index 100%
rename from example/put/main.go
rename to example/upload/main.go
diff --git a/sftp.go b/sftp.go
index 80bd23a..ebb477f 100644
--- a/sftp.go
+++ b/sftp.go
@@ -61,13 +61,13 @@ func (c *Client) downloadFile(remoteFile, local string) error {
rsum := c.Md5File(remoteFile)
ioutil.WriteFile(localFile+".md5", []byte(rsum), 755)
if FileExist(localFile) {
- // 1. 检测远程是否存在
if rsum != "" {
lsum, _ := Md5File(localFile)
if lsum == rsum {
- log.Println("sftp: 文件与本地一致,跳过上传!", localFile)
+ log.Println("sftp: 文件与本地一致,跳过下载!", localFile)
return nil
}
+ log.Println("sftp: 正在下载 ", localFile)
}
}
}
@@ -196,6 +196,7 @@ func (c *Client) UploadFile(localFile, remote string) error {
log.Println("sftp: 文件与本地一致,跳过上传!", localFile)
return nil
}
+ log.Println("sftp: 正在上传 ", localFile)
}
}
@@ -437,7 +438,7 @@ func (c *Client) Md5File(path string) string {
if c.IsNotExist(path) {
return ""
}
- b, err := c.Run("md5sum " + path)
+ b, err := c.Output("md5sum " + path)
if err != nil {
return ""
}
diff --git a/ssh.go b/ssh.go
index 78d5644..f6770a2 100644
--- a/ssh.go
+++ b/ssh.go
@@ -1,30 +1,84 @@
package ssh
import (
+ "bufio"
+ "bytes"
+ "errors"
"fmt"
+ "io"
"path/filepath"
)
-// Run Execute cmd on the remote host and return stderr and stdout
-func (c *Client) Run(cmd string) ([]byte, error) {
+// Run Execute cmd on the remote host for daemon service
+func (c *Client) Run(cmd string) {
session, err := c.SSHClient.NewSession()
if err != nil {
- return nil, err
+ return
}
defer session.Close()
- return session.CombinedOutput(cmd)
+ session.Start(cmd)
+ if err != nil {
+ fmt.Printf("exec command:%v error:%v\n", cmd, err)
+ }
+ fmt.Printf("Waiting for command:%v to finish...\n", cmd)
+ //阻塞等待fork出的子进程执行的结果,和cmd.Start()配合使用[不等待回收资源,会导致fork出执行shell命令的子进程变为僵尸进程]
+ err = session.Wait()
+ if err != nil {
+ fmt.Printf(":Command finished with error: %v\n", err)
+ }
+ return
}
-//Exec Execute cmd on the remote host and return stderr and stdout
-func (c *Client) Exec(cmd string) ([]byte, error) {
+//Exec Execute cmd on the remote host and bind stderr and stdout
+func (c *Client) Exec(cmd string) error {
+ session, err := c.SSHClient.NewSession()
+ if err != nil {
+ return err
+ }
+ defer session.Close()
+ // session.Run(cmd)
+ // return session.CombinedOutput(cmd)
+ stdout, err := session.StdoutPipe()
+ // stderr, err = session.StderrPipe()
+ if err != nil {
+ fmt.Println(err)
+ return err
+ }
+
+ var b bytes.Buffer
+ session.Stderr = &b
+ session.Start(cmd)
+ //创建一个流来读取管道内内容,这里逻辑是通过一行一行的读取的
+ reader := bufio.NewReader(stdout)
+
+ //实时循环读取输出流中的一行内容
+ for {
+ line, err2 := reader.ReadString('\n')
+ if err2 != nil || io.EOF == err2 {
+ break
+ }
+ print(line)
+ }
+
+ //阻塞直到该命令执行完成,该命令必须是被Start方法开始执行的
+ session.Wait()
+ if b.Len() > 0 {
+ return errors.New(b.String())
+ }
+ return nil
+}
+
+// Output Execute cmd on the remote host and return stderr and stdout
+func (c *Client) Output(cmd string) ([]byte, error) {
session, err := c.SSHClient.NewSession()
if err != nil {
return nil, err
}
defer session.Close()
-
- return session.CombinedOutput(cmd)
+ // session.Run(cmd)
+ // return session.CombinedOutput(cmd)
+ return session.Output(cmd)
}
// RunScript Executes a shell script file on the remote machine.