ls -lh | awk '/^-/{print}' | wc -l
ls -lhR | awk '/^-/{print}' | wc -l
find . -type f | grep -v '^\./\.' | wc -l
文件: mysql_back.sh
#!/bin/bash
# 以下配置信息请自己修改
mysql_user="username" #MySQL备份用户
mysql_password="password" #MySQL备份用户的密码
mysql_host="127.0.0.1"
mysql_port="3306"
mysql_charset="utf8" #MySQL编码
backup_db_arr=("databasename") #要备份的数据库名称,多个用空格分开隔开 如("db1" "db2" "db3")
backup_location=/home/huangjian/mysql_backup #备份数据存放位置,末尾请不要带"/",此项可以保持默认,程序会自动创建文件夹
expire_backup_delete="ON" #是否开启过期备份删除 ON为开启 OFF为关闭
expire_days=3 #过期时间天数 默认为三天,此项只有在expire_backup_delete开启时有效
# 本行开始以下不需要修改
backup_time=`date +%Y%m%d%H%M` #定义备份详细时间
backup_Ymd=`date +%Y-%m-%d` #定义备份目录中的年月日时间
backup_3ago=`date -d '3 days ago' +%Y-%m-%d` #3天之前的日期
backup_dir=$backup_location/$backup_Ymd #备份文件夹全路径
welcome_msg="Welcome to use MySQL backup tools!" #欢迎语
# 判断MYSQL是否启动,mysql没有启动则备份退出
mysql_ps=`ps -ef |grep mysql |wc -l`
mysql_listen=`netstat -an |grep LISTEN |grep $mysql_port|wc -l`
if [ [$mysql_ps == 0] -o [$mysql_listen == 0] ]; then
echo "ERROR:MySQL is not running! backup stop!"
exit
else
echo $welcome_msg
fi
# 连接到mysql数据库,无法连接则备份退出
mysql -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password <<end
use mysql;
select host,user from user where user='root' and host='localhost';
exit
end
flag=`echo $?`
if [ $flag != "0" ]; then
echo "ERROR:Can't connect mysql server! backup stop!"
exit
else
echo "MySQL connect ok! Please wait......"
# 判断有没有定义备份的数据库,如果定义则开始备份,否则退出备份
if [ "$backup_db_arr" != "" ];then
#dbnames=$(cut -d ',' -f1-5 $backup_database)
#echo "arr is (${backup_db_arr[@]})"
for dbname in ${backup_db_arr[@]}
do
echo "database $dbname backup start..."
`mkdir -p $backup_dir`
`mysqldump -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password $dbname --default-character-set=$mysql_charset | gzip > $backup_dir/$dbname-$backup_time.sql.gz`
flag=`echo $?`
if [ $flag == "0" ];then
echo "database $dbname success backup to $backup_dir/$dbname-$backup_time.sql.gz"
else
echo "database $dbname backup fail!"
fi
done
else
echo "ERROR:No database to backup! backup stop"
exit
fi
# 如果开启了删除过期备份,则进行删除操作
if [ "$expire_backup_delete" == "ON" -a "$backup_location" != "" ];then
#`find $backup_location/ -type d -o -type f -ctime +$expire_days -exec rm -rf {} \;`
`find $backup_location/ -type d -mtime +$expire_days | xargs rm -rf`
echo "Expired backup data delete complete!"
fi
echo "All database backup success! Thank you!"
exit
fi
mysql_back.sh
文件可以作为一个定时任务运行。
mysqldump -hlocalhost -uroot -p databasename > databasename_backup.sql
mysqldump -hlocalhost -uroot -p -d databasename > databasename_backup.sql
gzip -d databasename_backup.sql.gz
mysql -u root -p databasename < databasename_backup.sql
这个会还原到备份的那个时间点的所有数据,新增的数据,还是被删除掉的数据,都会被还原。
package main
import (
"fmt"
"net/http"
"net/http/httputil"
"net/url"
"github.com/MDGSF/utils/log"
)
func startSimpleHTTPService() {
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello world")
})
log.Fatal(http.ListenAndServe("127.0.0.1:8887", nil))
}
func handleDefault(w http.ResponseWriter, req *http.Request) {
log.Printf("handleDefault, %v %v", req.Method, req.URL.Path)
w.WriteHeader(200)
w.Write([]byte("OK"))
}
func startService() {
http.HandleFunc("/", handleDefault)
log.Fatal(http.ListenAndServe("localhost:8888", nil))
}
/*
proxy localhost:8889 request to localhost:8888
*/
func startReverseProxy() {
go startService()
rpURL, err := url.Parse("http://localhost:8888")
if err != nil {
log.Fatalf("err = %v", err)
}
apiReverseProxy := httputil.NewSingleHostReverseProxy(rpURL)
http.Handle("/api/", http.StripPrefix("/api/", apiReverseProxy))
log.Fatal(http.ListenAndServe(":8889", nil))
}
func startMux() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
log.Printf("mux handle, %v %v", req.Method, req.URL.Path)
w.WriteHeader(200)
w.Write([]byte("I'm mux."))
})
log.Fatal(http.ListenAndServe("localhost:8890", mux))
}
func startServer() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
log.Printf("mux handle, %v %v", req.Method, req.URL.Path)
w.WriteHeader(200)
w.Write([]byte("I'm http server mux."))
})
server := &http.Server{
Addr: "localhost:8891",
Handler: mux,
}
log.Fatal(server.ListenAndServe())
}
var muxTestable *http.ServeMux
func initMuxTestable() {
muxTestable = http.NewServeMux()
muxTestable.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
log.Printf("muxTestable handle, %v %v", req.Method, req.URL.Path)
w.WriteHeader(200)
w.Write([]byte("I'm muxTestable."))
})
}
func startMuxTestable() {
initMuxTestable()
log.Fatal(http.ListenAndServe("localhost:8892", muxTestable))
}
func middleLogin(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Info("middle login")
h.ServeHTTP(w, r)
})
}
func middleForDefault(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Info("middle Default handler")
h.ServeHTTP(w, r)
})
}
func startMiddleHTTP() {
mux := http.NewServeMux()
defaultHandler := func(w http.ResponseWriter, req *http.Request) {
log.Printf("middle default handle, %v %v", req.Method, req.URL.Path)
w.WriteHeader(200)
w.Write([]byte("I'm middle default handler."))
}
mux.Handle("/", middleForDefault(http.HandlerFunc(defaultHandler)))
log.Fatal(http.ListenAndServe("localhost:8893", middleLogin(mux)))
}
func main() {
go startSimpleHTTPService()
go startReverseProxy()
go startMux()
go startServer()
go startMuxTestable()
go startMiddleHTTP()
shutdown := make(chan struct{})
<-shutdown
}
package main
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"github.com/MDGSF/utils/log"
)
func TestMux(t *testing.T) {
initMuxTestable()
server := httptest.NewServer(muxTestable)
defer server.Close()
resp, err := http.Get(server.URL)
if err != nil {
log.Fatalf("URL = %v, err = %v", server.URL, err)
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
expected := "I'm muxTestable."
if string(content) != expected {
log.Fatalf("content = %v, expected = %v", content, expected)
}
}
man ssh
man ssh_config
重启 ssh 服务: sudo service ssh restart
常用参数:
-n: Redirects stdin from /dev/null. This must be used when ssh is run in the background.
-N: Do not execute a remote command. This is useful for just forwarding ports.
-T: Disable pseudo-terminal allocation.
-f: Requests ssh to go to background just before command execution.
~/.ssh/config
/etc/ssh/ssh_config
Host myhost
HostName 30.121.120.160
User root
Port 8822
IdentityFile /home/huangjian/.ssh/id_rsa
ServerAliveInterval 60
ServerAliveCountMax 525600
TCPKeepAlive yes
然后就可以使用 ssh myhost
来连接服务器了。
TCPKeepAlive
是开启 tcp 那一层的心跳。
ServerAliveInterval
和 ServerAliveCountMax
是 ssh 那一层的心跳机制。
ServerAliveInterval 60
是每隔 60 秒发送一个数据包。
ServerAliveCountMax
是一共要发送多少个,超过这个数量了连接就会断开。
如果你想要每 60 秒发送一个心跳包,一共保持 10 分钟,那么你可以这么使用:
ServerAliveInterval 60
ServerAliveCountMax 10
如果你想要每 60 秒发送一个心跳包,一共保持 1 小时,那么你可以这么使用:
ServerAliveInterval 60
ServerAliveCountMax 60
LocalForward 是把服务端的端口映射到本地电脑
LocalForward [本地ip地址:本地端口] [服务端服务的ip地址:服务端服务的端口]
例子:
把服务器上的 6379 端口映射到本地的 16379 端口,需要在配置文件中添加
LocalForward 127.0.0.1:16379 127.0.0.1:6379
命令 ssh -L 16379:127.0.0.1:6379 user@host
实现和上面相同的效果。
RemoteForward 是把本地的端口映射到服务器上
RemoteForward [服务端ip地址:服务端端口] [本地服务的ip地址:本地服务的端口]
RemoteForward 需要在服务器的配置文件 /etc/ssh/sshd_config 上开启 GatewayPorts yes
例子:
把本地的 8666 端口映射到服务器上的 18666 端口,需要在配置文件中添加
RemoteForward 127.0.0.1:18666 127.0.0.1:8666
命令 ssh -R 18666:127.0.0.1:8666 user@host
实现和上面相同的效果。
映射 biao 这个服务器上的端口 6379 到本地的 16379 端口。并且 autossh 会在后台监控 ssh 是否正常运行。
autossh -M 0 -f -nNTf -L 16379:127.0.0.1:6379 user@biao
把本地的 6000 端口映射到服务器上的 16000 端口。并且 autossh 会在后台监控 ssh 是否正常运行。
autossh -M 0 -f -nNTf -R 16000:127.0.0.1:6000 user@biao
把本地的 6000 端口映射到服务器上的 6000 端口。并且 autossh 会在后台监控 ssh 是否正常运行。
# autossh -M 0 -f -nNTf -R 6000:127.0.0.1:6000 user@biao -F /home/huangjian/.ssh/config
self
when used as first method argument, is a shorthand for self: Self
. There are also &self
, which is equivalent to self: &Self
, and &mut self
, which is equivalent to self: &mut self
.
Self
in method arguments is syntactic sugar for the receiving type of the method (i.e. the type whose impl
this method is in). This also allows for generic types without too much repetition.
https://stackoverflow.com/questions/32304595/whats-the-difference-between-self-and-self
/*
https://www.cs.brandeis.edu/~cs146a/rust/doc-02-21-2015/book/strings.html
https://www.cs.brandeis.edu/~cs146a/rust/doc-02-21-2015/book/more-strings.html
String and &str
String, is a heap-allocated string, is growable, is guaranteed to be UTF-8.
&str, is called string slices.
Like vector slices, string slices are simply a pointer plus a length.
This means that they're a 'view' into an already-allocated string, such as a string literal or a String.
Viewing a String as a &str is cheap, but converting the &str to a String involves allocating memory.
*/
fn main() {
test1();
test2();
}
/*
建议使用:在拥有所有权的地方使用 String,在租借出去的时候使用 &str
*/
fn test1() {
let s1 = "s1 hello world"; // s1: &str
let mut s2 = "s2 Hello".to_string();
s2.push_str(", world.");
take_slice(s1);
take_slice(&s2);
}
fn take_slice(slice: &str) {
println!("Got: {}", slice);
}
/*
.as_bytes() convert to &[u8].
.bytes() will iterate over the underlying bytes
.chars() will iterate over the code points
*/
fn test2() {
let s = "hello world.";
for c in s.bytes() {
print!("{} ", c);
}
println!();
for c in s.chars() {
print!("{} ", c);
}
println!();
}
bytes
和 chars
返回的是迭代器。
as_bytes
所有权借用。
as_bytes_mut
所有权可变借用。
into_bytes
所有权被转移了。