最近在学习go语言,把之前picbed的命令行cli.py用go重写,在编写过程中,go实现相应功能走了些 弯路,在本文拎出来分享给大家(新手)。
三端复制剪贴板
三端指的是Windows、Linux、macOS,实现用命令复制内容到系统剪贴板。
Windows
clip
echo hello world | clip
Linux
xclip
echo "hello world" | xclip -selection clipboard
macOS
pbcopy
echo "hello world" | pbcopy
使用golang调用带有管道符的命令
os/execsh -ccmd.exe /C
Linux/macOS
package main
import "fmt"
import "os/exec"
func main() {
content := "hello world"
// if macOS
// cmd := fmt.Sprintf(`echo "%s" | pbcopy`, content)
cmd := fmt.Sprintf(`echo "%s" | xclip -selection clipboard`, content)
err := exec.Command("bash", "-c", cmd).Run()
if err != nil {
fmt.Println("exec error")
}
}
Windows
package main
import (
"fmt"
"strings"
"os/exec"
)
func main() {
content := "hello world"
cmd := fmt.Sprintf(`echo %s | clip`, strings.ReplaceAll(content, "\n", "\\n"))
err := exec.Command("cmd.exe", "/C", cmd).Run()
if err != nil {
fmt.Println("exec error")
}
}
使用golang调用powershell触发Windows10桌面消息通知
powershell xxx.ps1 <Sub-Title></code></pre>
param(
[String] $Title,
[String] $SubTitle
)
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
$APP_ID = '110366bd-56e2-47ed-9bdf-3ce1fa408b6c'
$template = @"
<toast>
<visual>
<binding template="ToastText02">
<text id="1">$($Title)</text>
<text id="2">$($SubTitle)</text>
</binding>
</visual>
</toast>
"@
$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
$xml.LoadXml($template)
$toast = New-Object Windows.UI.Notifications.ToastNotification $xml
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($APP_ID).Show($toast)
在go程序中想调用它,我一时没想到别的方法,暂时思路是把内容保存为临时文件,再用 os/exec 调用, 如下示例(没有错误处理):
package main
import (
"fmt"
"os"
"os/exec"
"io/ioutil"
)
func main() {
sf := genTmpPS1()
exec.Command(
"powershell", "-ExecutionPolicy", "Unrestricted", sf,
"上传成功", "已复制到剪贴板",
).Run()
}
func genTmpPS1() (filepath string) {
tpl := []byte(`
param(
[String] $Title,
[String] $SubTitle
)
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
$APP_ID = '110366bd-56e2-47ed-9bdf-3ce1fa408b6c'
$template = @"
<toast>
<visual>
<binding template="ToastText02">
<text id="1">$($Title)</text>
<text id="2">$($SubTitle)</text>
</binding>
</visual>
</toast>
"@
$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
$xml.LoadXml($template)
$toast = New-Object Windows.UI.Notifications.ToastNotification $xml
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($APP_ID).Show($toast)
`)
tmpfile, err := ioutil.TempFile(os.TempDir(), "*.ps1")
tmpfile.Write(tpl)
tmpfile.Close()
return tmpfile.Name()
}
使用homebrew安装golang编译的可执行程序
go程序编译完成后就一个二进制的可执行文件,在macOS系统中,可以自建一个Tap方便homebrew安装。
相关概念可以参考 使用 Homebrew 维护自己的软件仓库 这篇文章,这里不再赘述。
新发布程序
homebrew-XXX
以picbed-cli的发行版为例, 我已经编译了macOS版本的压缩包,在release中有附件,压缩包里只有一个picbed-cli可执行文件。
打开macOS终端,执行命令:
brew create 程序包网络下载地址
xxx.rbdef installsystem ./configurebin.install
class PicbedCli < Formula
desc "picbed client cli"
homepage "https://github.com/staugur/picbed-cli"
url "https://static.saintic.com/download/picbed-cli/picbed-cli.0.4.2-darwin-amd64.tar.gz"
sha256 "c33ae9aae32273e9ea681eff904bfbae912753e7afa0175ad69765fe17b002ff"
def install
bin.install "picbed-cli"
end
test do
system "false"
end
end
brew create
示例内容保存为xxx.rb提交到你的git仓库 homebrew-XXX 中
更新程序版本
只需要编辑git仓库homebrew-XXX下的xxx.rb,修改url为新版本压缩包路径、sha256为新版本压缩包 sha256值,再提交后即可。
brew update && brew upgrade picbed-cli
其他经验补充说明
ldflags -X
-i/--infoldflag -X
go build -ldflags "-s -w -X main.commitID=xxx -X main.built=xxx"
这个程序比较简单,就一个main包,传入没什么问题。
不过有时候你可能想往子包中传值,参考这篇文章:使用ldflags设置Go应用程序的版本信息
假如你的程序目录结构如下:
rtfd
├── cmd
│ └── root.go
├── go.mod
├── main.go
├── Makefile
└── VERSION
其中main.go是main包,cmd下go文件属于cmd包,按照上面文章应该这么传值:
$ go build -ldflags "-X cmd.commitID=xxx -X cmd.built=xxx"
$ go build -ldflags "-X rtfd/cmd.commitID=xxx -X rtfd/cmd.built=xxx"
均失败!
-ldflags="-X 'package_path.variable_name=new_value'"
可能是新手,没搞明白package_path含义,google也是没找到教新的分享, 捣鼓好久突然灵机一动,改为这么传值:
go build -ldflags "-X tcw.im/rtfd/cmd.commitID=xxx -X tcw.im/rtfd/cmd.built=xxx"
行了!
go module
此刻,好想吐槽(自己?)
废话太多了,分享的大概意思就是:
go modulego build -ldflag -Xpackage_pathmodulego build -ldflag -X module/package_path.variable_name=value