Linux

Linux 磁盘管理命令

挂载磁盘

mount 命令,用于挂载磁盘以及显示相关信息

mount 显示挂载信息
mount -t TYPE OPTIONS DEVICE DIRECTORY
比如:
     mount -t vfat /dev/sdb1 /mnt/media

常用的参数

-a 挂载 /etc/fstab 中的所有文件
-f 模拟挂载
-r 只读挂载
-w 读写挂载(默认)
-L 指定 lebel
-u 指定 uuid
-o 选项
    ro 只读
    rw 读写
    user 允许普通用户挂载
    check=none 不检查错误
    loop 挂载文件,比如 iso
    nofail 失败了也不要汇报
    remount
--bind 选择新的挂载点作为 alias `mount --rbind olddir newdir`
--move 移动到新的挂载点 `mount --move olddir newdir`

使用 mount 命令的最佳实践是在 /etc/fstab 中先输入需要挂载的磁盘对应的配置,然后使用 mount -a 挂载。这样避免在 /etc/fstab 中挂载的命令是错的导致无法开机。

卸载

umount DIRECTORY/DEVICE 卸载设备

磁盘使用

  • 查看分区的 uuid:ll /dev/disk/by-uuid。在 etc/fstab 中挂载磁盘最好使用 uuid
  • 查看分区的类型:parted -l
  • df show free disk spaces
  • du show disk usage infomation。du -sh ls # great command
  • dd disk dump

分区与格式化

fdisk DEVICE

p   print partition table
n   new partition
w   write back to table
d   删除分区

创建文件系统

mkfs.ext4 PARTITION

fsck check a file system

逻辑卷

硬盘称作物理卷,多个物理卷构成一个卷组,一个卷组可以分成多个逻辑卷

fzf – 命令行模糊查找工具

安装

在 mac 上直接 brew install fzf 就好了

使用

调用 fzf 命令

直接在命令行输入 fzf 开始模糊查找。

查找命令 | 匹配类型 | 说明
——|————|—————
sbtrkt|模糊匹配 | 匹配 sbtrkt
^music|前缀精确匹配 | 以 music 开头
.mp3^|后缀精确匹配 | 以.mp3 结尾
‘wild |精确匹配 (quoted) | 精确包含 wild
!fire | inverse-exact-match | 不包含 fire
!.mp3$ | inverse-suffix-exact-match | 不以.mp3 结尾

|可以做 or 匹配, 比如 ^core go$|rb$|py$ 表示以 core 开头,以 go 或 rb 或 py 结尾的

按键

ctrl-j/k 或者 ctrl-n/p 或者箭头来上下选择
ctrl-c 或者 Esc 退出
Enter 选择
在多行模式,tab 和 Shift-tab 来标记文件

除了这些按键之外,还可以使用 --bind 绑定自己的按键,见下文

选中之后,fzf 的默认操作是打印这个文件名,这样我们还得打开,所以可以直接 vim $(fzf) 也就是使用 vim 打开我们选中的文件。

使用快捷键

Ctrl-T 快速选择当前目录文件,并把文件名打印出来
Ctrl-R 使用 fzf 来过滤 history 命令
ALT-C cd 进入选中的目录

自动补全

fzf 支持不少命令的自动补全功能,通过 ** 来触发。如果没有特殊支持某个命令的话,fzf 会用文件来补全。

vim **<tab>
cd **<tab>
ssh **<tab>  从 /etc/hosts 中读取主机列表
unset **<tab>
export **<tab>
unalias **<tab>

kill -s TERM <tab>

这里我把触发按键设置成了 Ctrl-Y 比原生的触发更方便一点,如何配置见下文。

选项

--height xx% 默认情况下 fzf 占据了 100% 的屏幕
--reverse 提示符在上面
--bind 绑定命令
--preview 指定预览命令

默认情况下,在 fzf 中选中文件之后知识打印出这个文件名,可以使用 bind 来指定一些快捷键,来对文件的一些操作。

比如:

# Press F1 to open the file with less without leaving fzf
# Press CTRL-Y to copy the line to clipboard and aborts fzf (requires pbcopy)
fzf --bind "f1:execute(less -f {}),ctrl-y:execute-silent(echo {} | pbcopy)+abort"

默认情况下,fzf 不会预览文件的内容,可以使用 –preview 指定,

# Use head instead of cat so that the command doesn"t take too long to finish
fzf --preview "head -100 {}"

语法高亮

fzf --preview "[[ $(file --mime {}) =~ binary ]] &amp;&amp;
                 echo {} is a binary file ||
                 (highlight -O ansi -l {} ||
                  coderay {} ||
                  rougify {} ||
                  cat {}) 2> /dev/null"

相关的环境变量

默认情况下,fzf 从 find * -type f 中读取文件列表,可以使用更好用的 fd 来替换。

export FZF_DEFAULT_OPTS="--height 40% --reverse --border" 这个变量来指定默认选项。
export FZF_DEFAULT_COMMAND="fd --type f" 来指定
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"

我的最终配置

[ -f ~/.fzf.zsh ] &amp;&amp; source ~/.fzf.zsh

export FZF_DEFAULT_COMMAND="fd --type f"
export FZF_CTRL_T_COMMAND="fd --type f"
export FZF_ALT_C_COMMAND="fd --type d"
export FZF_COMPLETION_TRIGGER=""
export FZF_DEFAULT_OPTS="--height 40% --reverse --border --prompt ">>>" \
    --bind "alt-j:preview-down,alt-k:preview-up,alt-v:execute(vi {})+abort,ctrl-y:execute-silent(cat {} | pbcopy)+abort,?:toggle-preview" \
    --header "A-j/k: preview down/up, A-v: open in vim, C-y: copy, ?: toggle preview" \
    --preview "(highlight -O ansi -l {} 2> /dev/null || cat {} || tree -C {}) 2> /dev/null""
export FZF_CTRL_T_OPTS=$FZF_DEFAULT_OPTS
export FZF_CTRL_R_OPTS="--preview "echo {}" --preview-window hidden:wrap --bind "?:toggle-preview""
export FZF_ALT_C_OPTS="--height 40% --reverse --border --prompt ">>>" \
    --bind "alt-j:preview-down,alt-k:preview-up,?:toggle-preview" \
    --header "A-j/k: preview down/up, A-v: open in vim, C-y: copy, ?: toggle preview" \
    --preview "tree -C {}""
bindkey "^Y" fzf-completion
bindkey "^I" $fzf_default_completion
[ -f ~/.dotfiles/lib/fzf-extras.sh ] &amp;&amp; source ~/.dotfiles/lib/fzf-extras.sh

fd – 更好的 find 命令(fd – A nicer find command)

fd(https://github.com/sharkdp/fd ) 是 find 命令的一个更现代的替换。

fd(https://github.com/sharkdp/fd ) is a modern and nicer replacement to the traditional find command.

对比一下 Some comparisons

查找名字含有某个字符的文件 Find a filename with certain string

OLD

-> % find . -name "*hello*"
./courses/hello_world.go
./courses/chapter_01/hello_world.go
./courses/chapter_01/hello_world
./examples/01_hello_world.go

NEW

-> % fd hello
courses/chapter_01/hello_world
courses/chapter_01/hello_world.go
courses/hello_world.go
examples/01_hello_world.go

使用正则表达式查找 Find files using regular expression

比如说查找符合 \d{2}_ti 模式的文件。find 使用的正则表达式非常古老,比如说在这里我们不能使用 \d,也不能使用 {x} 这种语法。因此我们需要对我们的正则表达式做一些改写。关于find支持的正则表达式这里就不展开了。

fd 默认就是使用的正则表达式作为模式,并且默认匹配的是文件名;而 find 默认匹配的是完整路径。另外

For example, let’s find a file whose name matches \d{2}_ti. find uses a very ancient form of regular expression. Neither can we use \d, nor can we use {x}. So we have to adjust our expression to these kind of limitations.

fd, by default, uses regular expression as patter, and matches filenames; on the other hand, find uses the -regex option to specify a regular expression, and it matches the whole path.

OLD

-> % find . -regex ".*[0-9][0-9]_ti.*"
./examples/33_tickers.go
./examples/48_time.go
./examples/28_timeouts.go
./examples/50_time_format.go
./examples/32_timers.go

NEW

-> % fd "\d{2}_ti"
examples/28_timeouts.go
examples/32_timers.go
examples/33_tickers.go
examples/48_time.go
examples/50_time_format.go

指定目录 Find in a specific directory

find 的语法是 find DIRECTORY OPTIONS;而 fd 的语法是 fd PATTERN [DIRECTORY]。注意其中目录是可选的。这点个人认为非常好,因为大多数情况下,我们是在当前目录查找,每次都要写 . 非常烦。

find follows the syntax find <directory> <options>; meanwhile, fd uses fd <pattern> [<directory>]. Note that the directory part is optional. AFAIK, this is very convenient. Most of the times, we are just trying to find something in the working directory, typing . each time is very annoying.

OLD

-> % find examples -name "*hello*"
examples/01_hello_world.go

NEW

-> % fd hello examples
examples/01_hello_world.go

直接执行命令 Execute the command without arguments

find 会打印帮助信息,而 fd 则会显示当前目录的所有文件。

find will print help message, fd will print all the files in current directory

OLD

-> % find
usage: find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]
       find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression]

NEW

-> % fd
courses
courses/chapter_01
courses/chapter_01/chapter_1.md
courses/chapter_01/chapter_1.pdf
courses/chapter_01/hello_world
courses/chapter_01/hello_world.go

按后缀名查找文件 Find files by extension

这是一个很常见的需求,find 中需要使用 -name "*.xxx" 来过滤,而 fd 直接提供了 -e 选项。

It’s a very common use case. With find, you have to use -name "*.xxx", while fd provides -e option directly.

OLD

-> % find . -name "*.md"
./courses/chapter_01/chapter_1.md
./courses/chapter_1.md

NEW

-> % fd -e md
courses/chapter_01/chapter_1.md
courses/chapter_1.md

查找中过滤掉 .gitignore 中的文件 Exclude files listed in .gitignore

find 并没有提供对 .gitingnore 文件的原生支持,更好的方法可能是使用 git ls-files。而作为一个现代工具,fd 则默认情况下就会过滤 gitignore 文件,更多情况请查阅文档。

可以使用 -I 来包含这些文件,使用 -H 添加隐藏文件。

find does not natively support .gitignore files, a practical way would be using git ls-files. As a modern tool, fd ignores files listed in .gitignore and hidden files by default.

You could use -I to include those files, -H to also include hidden files.

OLD

-> % git ls-files | grep xxx

NEW

-> % fd xxx

排除某个文件夹 Exclude a directory

fd provides a -E option to exclude directories. You could put the directories in .fdignore, too.

OLD

-> % find . -path ./examples -prune -o -name "*.go"
./courses/hello_world.go
./courses/chapter_01/hello_world.go
./examples

NEW

-> % fd -E examples ".go$"
courses/chapter_01/hello_world.go
courses/hello_world.go

使用 xargs Using xargs

一般来说,如果使用管道过滤的话,需要使用 ‘\0’ 来作为字符串结尾,避免一些潜在的空格引起的问题。

find 中需要使用 -print0 来调整输出 ‘\0’ 结尾的字符串,在 xargs 中需要使用 -0 表示接收这种字符串。而在 fd 中,和 xargs 保持了一直,使用 -0 参数就可以了。

If you are using pipes to filter results, using \0 other than \n would be a better option to avoid some potential problems.

find with -print0 will output \0-terminated strings, and xargs‘s option is -0 to process them. fd chooses -0 as its option, which is consistent with xargs.

OLD

-> % find . -name "*.go" -print0 | xargs -0 wc -l
       7 ./courses/hello_world.go
       7 ./courses/chapter_01/hello_world.go
      50 ./examples/07_switch.go
...

NEW

-> % fd -0 -e go | xargs -0 wc -l
       7 courses/chapter_01/hello_world.go
       7 courses/hello_world.go
       7 examples/01_hello_world.go
...

总之,fd 命令相对于 find 来说相当简单易用了

As you can see, using fd can save you a lot of keystrokes.

PS

使用 exec Using exec

OLD

-> % find . -name "*.md" -exec wc -l {} \;
     114 ./courses/chapter_01/chapter_1.md
     114 ./courses/chapter_1.md

NEW

You could also omit the {}

-> % fd -e md --exec wc -l {}
     114 courses/chapter_1.md
     114 courses/chapter_01/chapter_1.md

Linux 命令行查看系统信息

查看机器名

uname -a # view system name
arch # show arch

查看 ubuntu 版本

show ubuntu version

cat /etc/*release

查看内存使用

free -mh

(master)[email protected] ~ $ free -mh
             total       used       free     shared    buffers     cached
Mem:          251G       241G       9.8G       5.9G       4.3G        76G
-/+ buffers/cache:       161G        90G
Swap:           0B         0B         0B

含义,第一行表示实际的内存占用情况,linux 的机制是尽可能多的占用内存,所以 free 往往很小;但是占用的内存不一定都在被使用,也就是最后的 buffers 和 cached 内存是被系统预先占用的。
在第二行把这两项抛出,就是你的实际内存占用 161G,实际可使用内存 90G

iostat 和 vmstat

vmstat -awS M

(master)[email protected] ~/repos/crawl_deploy/svc_ctl $ vmstat -a
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free  inact active   si   so    bi    bo   in   cs us sy id wa st
57  0      0 197155680 3614480 57558348    0    0     8    39    0    0  6  2 91  0  0

查看内存使用情况,其中最重要的是 free 和 si、so 三列,其中 free 表示空闲内存,si 表示 swap in,so 表示 swap out

vmstat INTERVAL TIMES 执行 vmstat 每 INTERVAL 秒,并且执行 TIMES 次

http://www.orczhou.com/index.php/2010/03/iostat-detail/

命令行的一些小技巧

最近工作中经常用到的一些组合命令,本来想提交到 commandlinefu.com 上,但是忘记了密码,怎么也登录不上去了,记到这里吧

  • 脚本所在的目录
dirname $0
  • 文件夹下面按照占用空间大小排序
du -sh &#x60;ls&#x60; | sort -rh
  • 返回上一个目录
cd -
  • 显示所有的日志的最后几行
tail *
  • set
set -x # 显示每个执行的命令
set -e # 当有程序返回非 0 值时直接退出,相当于抛出异常
  • here doc
cat << EOF > /tmp/yourfilehere
These contents will be written to the file.
        This line is indented.
EOF
  • 删除包含某个关键字的所有行
fd -t f -0 | xargs -0 sed -i /KeyWord/d
  • 在 shell 中,所有字符串都要用引号包围

Always quote strings in bash. If you string is empty and you are testing it with == or !=, then there will be a “== is not uniary operator” error

  • 替换一个文件夹下的所有文件
fd . -t file -0 | xargs -0 sed -i -e "s/make_redis_client/create_redis_client/g"

from: https://stackoverflow.com/questions/6758963/find-and-replace-with-sed-in-directory-and-sub-directories

Linux 内存与进程管理(ps/top/kill…)

ps 命令

比较有用的选项有

-e 显示所有的进程
-f 显示 uid, pid, ppid, cpu, starttime, tty, cpu usage, command
-j 显示 user, pid, ppid, pgid, sess, jobc, state, tt, time, command。个人更喜欢 -j 一点
-l 显示 uid, pid, ppid, flags, cpu, pri, nice, vsz=SZ, rss, wchan, state=S, paddr=ADDR, tty, time, and command=CMD.
-v 显示 pid, state, time, sl, re, pagein, vsz, rss, lim, tsiz, %cpu, %mem, and command

-L 显示能够排序的关键字(mac)
L 显示能排序的关键字(Linux)
-o/-O 指定显示的列,-o 只显示指定的列,-O 有默认的几列,等价于:-o pid,format,state,tname,time,command

-S 把所有已经退出的进程的时间计算到父进程上(mac)
S 把所有已经退出的进程的时间计算到父进程上(Linux)
-u 按照 uid/username 过滤
-p/--pid 限制 pid
-g/--gid 限制 gid
-C 按照命令过滤
--ppid 按照 ppid 过滤
--ssid 按照 ssid 过滤
--tid 按照 tty 过滤

-E 显示环境变量
-H/--forest 按照进程树显示

--sort 按照某一列排序

-ww 不要限制显示的输出宽度

例子

  1. 使用 ps 显示占用内存最多的进程
% ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head
  1. 显示所有进程树
% ps -ejH

其他相关命令

pstree 查看进程树

pgrep process_name 按照名字查找进程 pid

top 命令

定时刷新系统的进程状态的监控程序。mac 上的默认排序是 pid,Linux 上是 %CPU。mac 上的 top 程序和 Linux 上非常不一样。

  • top 教程:https://linoxide.com/linux-command/linux-top-command-examples-screenshots/
  • htop 教程:http://www.cnblogs.com/lizhenghn/p/3728610.html
  • atop 教程:http://www.cnblogs.com/bangerlee/archive/2011/12/23/2294090.html

atop

atop 用来分析机器在历史上的负载情况。通过 crontab 固定时间采样,组合起来形成一个 atop 日志文件,可以使用 atop -r XXX 对日志文件查看。

atop 每天以一个 /var/log/atop/atop_YYYYMMDD 的形式生成一个日志文件。

常用命令

  • b mm:ss 到指定时间
  • t 查看后十秒
  • T 查看前十秒
  • m 按照内存排序
  • C 按照 CPU 排序
  • c 查看详细命令

kill 命令系列

kill -s SIGNAL pid

或者 pkill xxx,不要使用 killall ,use pkill over killall

调整 nice 值

使用 nice 和 renice。nice 的范围是 -20 ~ 19,nice 值越低,优先级越高。

nice -n 10 COMMAND # 以 10 为初始 nice 值启动命令
renice 10 -p pid

jobs 命令相关

jobs list all jobs

command & put job in the background

fg N to put it in the foreground

bg N to put it in the background

ctrl-z to put a job to sleep

kill %n to kill job number n

lsof

lsof -i:port 列出指定端口对应的进程

lsof -u username 指定用户

lsof -c process_name 指定进程名

lsof -p pid 指定 pid

使用 dmesg 查看当前的内核日志,debian 上可以查看 /var/log/kern.log /var/log/dmesg.0

RSS is Resident Set Size (physically resident memory – this is currently occupying space in the machine’s physical memory), and VSZ is Virtual Memory Size (address space allocated – this has addresses allocated in the process’s memory map, but there isn’t necessarily any actual memory behind it all right now).[1]

galance

https://github.com/nicolargo/glances

[1] https://stackoverflow.com/questions/7880784/what-is-rss-and-vsz-in-linux-memory-management

shell 编程教程

变量和值

variables are referenced by $var or ${var}. Global variables are visible to all sub bash sessions, and are often called env variables, local variables are only visible to local session, not subsessions.

Global variables can be viewed as env, and can be created by export.

TEST=testing; export $TEST # or
export TEST=testing # NOTE: no $

Useful variables

HOME    Same to ~
IFS
PATH    Search path
EUID    User id
GROUPS  Groups for current user
HOSTNAME    Hostname
LANG
LC_ALL
OLDPWD
PWD

定义和使用变量

定义变量,注意因为 shell 中的语法使用空格作为命令分割的限制,等于号前后不能加空格。

FOO=bar

使用变量,需要添加上 $ 符号。

echo $FOO

字符串在双引号中可以直接插入,这时候要加上大括号来指示变量名的起始位置。

echo "${FOO}xxx"

变量默认实在当前的回话中可见的,而不会作为环境变量传递给调用的命令。可以使用 export 导出变量,或者在命令前加上指定的环境变量。

-> % cat env.py
import os
print("FOO env variable is: ", os.environ.get("FOO"))

-> % python3 env.py
FOO env variable is:  None

-> % FOO=bar python3 env.py
FOO env variable is:  bar

使用 export

-> % export FOO=bar
-> % python3 env.py
FOO env variable is:  bar

一些有用的内置变量

$HOME     家目录,比如 /home/kongyifei
$IFS      默认的分隔符,和 for 循环紧密相关
$PATH     搜索路径,当你执行 ls 的时候,shell 会在这个变量中查找 ls 命令
$EUID     当前有效用户 ID
$LANG
$LC_ALL
$OLDPWD   上一个工作目录
$PWD      当前工作目录

数组

使用小括号来定义一个数组,关于 for 循环随后会讲

A=(1 2 3)

for el in ${A[@]}; do
    echo $el
done

字符串操作

大括号里面的字符串会被展开成独立的字符串

% echo {1,2,3,4}
1 2 3 4
% mkdir -p test/{a,b,c,d}{1,2,3,4}
% ls test/
a1  a2  a3  a4  b1  b2  b3  b4  c1  c2  c3  c4  d1  d2  d3  d4
% mv test/{a,c}.conf  # 这个命令的意思是:mv test/a.conf test/c.conf

切片:${string:start:length}

默认值 ${var:-default}

设定值 ${var:=default}

长度 ${#var}

字符串 Expansion and slice

[[email protected] bash]$ mkdir -p test/zorro/{a,b,c,d}{1,2,3,4}
[[email protected] bash]$ ls test/zorro/
a1  a2  a3  a4  b1  b2  b3  b4  c1  c2  c3  c4  d1  d2  d3  d4

[[email protected] bash]$ mv test/{a,c}.conf
这个命令的意思是:mv test/a.conf test/c.conf

${string:start :length} string slice

default value: ${var:-default}
set value: ${var:=default}

${#var} get variable length

Redirection

input: <, output >, append >>

cat > file << EOF
this
line
will
be redirected to
file
EOF

pipe

pipe commands will be run simultaneously, but the second command will wait for the input

Sub shell

use $(expression)

控制语句

条件语句

if 语句成立的条件是 expr 返回值为 0。

if expr; then
    statement;
elif expr; then
    statement;
else
    statement;
fi

test command

虽然可以使用任意的语句作为判断条件,不过我们一般情况下都是用 [ 这个命令来作为判断条件的,需要注意的是 [ 并不是一个语法,而是一个命令。不过由于 [ 这个上古命令实在功能太少,现在一般采用 [[ 来作为判断条件。

if [[ "a" == "b" ]]; then
    echo "wtf"
else
    echo "meh"
fi

[[支持的条件有

1 数值比较,仅限整数,注意不能使用 > < 等符号。

n1 -eq n2   equal
n1 -ge n2   greater or equal
n1 -gt n2   greater
n1 -le n2       less or equal
n1 -lt n2   less
n1 -ne n2   not equal

2 字符串比较

Note: Variables may contain space, so the best way to comparison is to add quotes: "$var1" = "$var2"

str1 == str2    equal
str1 != str2    not equal
str1 < str2 less
str1 > str2 greater
-z str  zero
-n str  not zero length

3 file comparison

-d  is directory?
-e  exist?
-f  is regular file?
-r  exist and readable?
-s  exist and has content
-w  exist and writable
-x  exist and executealbe
-O  exist and owned
-G  exist and in same group
file -nt file2  newer than
file1 -ot file2     older than

case

case var in
parttern | pattern2) commands;;
pattern3) commands2;
*) default commnads;;
esac

Loops

foreach 语句

for var in list; do
echo $var
done

其中 list 可以是一个数组,也可以是一个被 $IFS 分割的字符串。默认情况下,$IFS 是 ” \n\t”。其中包含了空格。

如果要覆盖 IFS,一般这样使用:

OLDIFS=$IFS
IFS=”\n” # new seperator

do things

IFS=$OLDIFS

while-loop

until/while expr; do
# commands
done

pipe

the result of a for loop is pipe-able to other command

for city in beijing shanghai; do
    echo $city is big
done > cities.txt
# will save the result in cities.txt

输入输出

命令行参数

parameters to a script can be obtained as $1, $2, $3…。 $0 is the script name, remember to check whether the parameter is empty. $# is the number of parameters(without script name).

$0  script name / function name
$1...$x command line arguments / parameters
$#  number of arguments(without $0)
$*  all parameters as a string
[email protected]  all parameters as a string list

shift

processing parameters using shift,

while [ -n “$1” ]; do
case “$1” in
-a) echo “option -a” ;;
–) shift
break;;
*) echo “$1” is not a option ;;
esac
shift
done

read

read OPTIONS VARNAME read input to variables

  • read -p Prompt
  • read -t timeout
  • read -s hide input

we can use read to read file or stdin

redirection

2> redirect STDERR
m>&n redirect fd m to fd n’s associated file

Note: you have to use command >> command.log 2>&1 (put 2>&1 at the end), since this means redirect 2 to 1’s
in a scirpt
exec 2> filename # reopen stdout to filename

Signal

trap commnad signal is used to handle signals in shell

Functions

有两种定义函数的方式

function name {
    # function body
}

foo() {
    # function body
}

要调用上面这个函数,直接就输入

foo

就好了

return

shell functions behave like a small script, and it does NOT return a computed value…It retures a exit code, which is between 0 and 255. if no return is specified, the exit code of last command will be returned

You can read the return value by $? like any normal commands

the right way to to return a value from function, you will have to echo out the value, and put the function is subshell

function foo {
    # do some compute
    echo $result;
}

retval=$(foo)

Note: any thing that echos in the function body will be captured, so please keep that from happen

parameters

like a shell script, $0 holds the function name, $1 … $9 holds the parameters, $# is the num of parameters

local variables

use local to declare local variables

alias

alias new_name="command string"
$ \command  # bypass alias

debugging

DEBUG macro

multiprocess

PIDARRAY=()
for file in filelist; do
md5sum file &;
PID
ARRAY+=(“$!”)
done
wait ${PID_ARRAY[@]}

使用 systemd 部署守护进程

大多数的 Linux 系统已经选择了 systemd 来作为进程管理器。之前打算使用 supervisord 来部署服务,思考之后发现还不如直接使用 systemd 呢。这篇文章简单介绍下 systemd。

例子

我们从一个例子开始,比如说我们有如下的 go 程序:

package main

import (
    fmt
    net/http
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, Hi there!)
}

func main() {
    http.HandleFunc(/, handler)
    http.ListenAndServe(:8181, nil)
}

编译到 /opt/listen/listen 这里。首先我们添加一个用户,用来运行我们的服务:

adduser -r -M -s /bin/false www-data

记下这条命令,如果需要添加用户来运行服务,可以使用这条。

Unit 文件

Unit 文件定义了一个 systemd 服务。/usr/lib/systemd/system/ 存放了系统安装的软件的 unit 文件,/etc/systemd/system/ 存放了系统自带的服务的 unit 文件。 我们编辑 /etc/systemd/system/listen.service 文件:

[Unit]
Description=Listen

[Service]
User=www-data
Group=www-data
Restart=on-failure
ExecStart=/opt/listen/listen
WorkingDirectory=/opt/listen

Environment=VAR1=whatever VAR2=something else
EnvironmentFile=/path/to/file/with/variables

[Install]
WantedBy=multi-user.target

然后

systemctl enable listen
systemctl status listen
systemctl start listen

其他一些常用的操作还包括:

systemctl start/stop/restart    
systemctl reload/reload-or-restart  
systemctl enable/disable    
systemctl status    
systemctl is-active 
systemctl is-enabled
systemctl is-failed
systemctl list-units [--all] [--state=]    
systemctl list-unit-files
systemctl daemon-reload 
systemctl cat [unit-name]   
systemctl edit [uni-name]
systemctl list-dependencies [unit]

依赖管理

In that case add Requires=B and After=B to the [Unit] section of A. If the dependency is optional, add Wants=B and After=B instead. Note that Wants= and Requires= do not imply After=, meaning that if After= is not specified, the two units will be started in parallel. if you service depends on another service, use requires= + after= or wants= + after=

尚未研究的问题:如何使安装的服务开机启动?是更改 wantedby 吗?如果是,wantedby 的值应该是什么? 对于 nginx 这样的 daemon 服务如何管理?

类型

Type: simple / forking 关于每个字段的含义,可以参考 这篇文章

使用 journalctl 查看日志

首先吐槽一下,为什么要使用 journal 这么一个拗口的单词,叫做 logctl 不好么

journalctl -u service-name.service

还可以添加 -b 仅查看本次重启之后的日志。

有时候 journald 占用的空间会过多,这时候可以压缩一下:

$ journalctl --disk-usage
Journals take up 3.8G on disk.

vi /etc/systemd/journald.conf

SystemMaxUse=50M

sudo systemctl restart systemd-journald

启动多个实例

  1. https://unix.stackexchange.com/questions/288236/have-systemd-spawn-n-processes
  2. http://0pointer.de/blog/projects/instances.html
  3. https://unix.stackexchange.com/questions/130786/can-i-remove-files-in-var-log-journal-and-var-cache-abrt-di-usr

Linux 命令行网络相关命令学习

iptables

使用 iptables -A 添加路由规则,使用 iptables -D 删除路由规则

fuser

查看哪个程序占用了给定端口

fuser XXX/tcp  # see which program is using tcp port XXX
fuser XXX/upd  # see which program is using udp port XXX
fuser -k XXX/tcp  # kill the program, if you have right permissions

curl

wget 功能很有限,httpie 虽然比较人性化但是有很多 bug,还是 curl 比较好用。

curl -L/--follow http://example.com           follow redirect
curl -I/--head http://example.com             only headers
curl -o/--output file http://example.com      http -d
curl -v/--verbose http://example.com
curl --data "key=value" http://example.com
curl --data-urlencode "key=
curl -X/--request GET/POST http://example.com
curl -H/--header "Accept: utf-8"
curl --referer http://x.com http://example.com
curl --user-agent

curl –cookie

使用代理

curl -x <protocol>://<user>:<password>@<host>:<port> --proxy-anyauth <url>

cookies

cookies 功能主要通过两个选项实现 -b/--cookie-c/--cookie-jar. --cookie 用于发送请求时
携带 Cookies, --cookie-jar 会把返回的 Cookie 按照 cookie.txt 规范存储到给定的文件中。

curl -v --cookie "USER_TOKEN=Yes" http://127.0.0.1:5000/
curl -v --cookie example.txt http://example.com

需要注意的是,如果 --cookie 的参数中包含了 =, 他就会被当做一个键值对来处理,而且可以
使用多个 Cookie, 用分号分开即可:”key1=val1;key2=val2;…”. 否则的话,这个参数会被当做文
件名,会读取对应文件的 Cookie, 这个文件同样要遵守 cookie.txt 的协议。

查看网络情况

需要注意的是,在 Linux 上 netstat 已经废弃了,应该使用新的 ss 命令。不过在 macOS 等 Unix 系统中,还是只有 netstat

netstat -a  list all ports
netstat -at list all tcp ports
netstat -l  all listening ports

netstat -in 查看提供网络接口的信息

netstat -rn 显示路由表

ifconfig eth0 显示接口的状态

ifconfig -a 所有接口的状态

ip addr eth0 全新的命令

Mac

和 Linux 基本相同,但是缺少 ip 指令,需要安装 iproute2mac 包

traceroute

nslookup

host

wget –noproxy

mtr

bt download

sudo add-apt-repository ppa:t-tujikawa/ppa
sudo apt-get update
sudo apt-get install aria2

使用 rsync 同步

rsync -azP localdir remotedir

  • -a archive,表示归档
  • -n dry-run,只显示要执行的操作而不具体执行
  • -z compress,压缩
  • -P –progress + –partial,显示进度同时断点续传
  • --exclude=<dir> exclude directory from being rsynced,这个目录是相对于源目录的

默认情况下,rsync 使用增量同步,而不会删除文件。使用 --delete 删除文件

参考资料

  1. https://curl.haxx.se/docs/http-cookies.html
  2. https://unix.stackexchange.com/questions/83394/rsync-exclude-directory-not-working