linux 常用知识

217 阅读7分钟

标签(空格分隔): linux


[TOC]

文档

鸟哥的私房菜

echo -e:激活转义字符

各种括号的用法

# /Users/liujunyang/work/xuetang/deploy/new_deploy.sh
work_dir=$(cd `dirname $0`; pwd)

UNIX 高手的 10 个习惯

系统版本

鸟哥文档 公司跳板机使用的 red hat

RPM 軟體管理
商業公司	RHEL (Red Hat 公司)  SuSE (Micro Focus)
社群單位	Fedora CentOS OpenSuSE	Debian
B2D	Gentoo

DPKG 軟體管理
商業公司 Ubuntu (Canonical Ltd.)	
社群單位 Debian B2D

如何查看Linux版本信息

# cat /proc/version
[ec2-user@buildserver nodejs-deploy]$ cat /proc/version
Linux version 4.4.30-32.54.amzn1.x86_64 (mockbuild@gobi-build-60008) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC) ) #1 SMP Thu Nov 10 15:52:05 UTC 2016

# uname -a
[ec2-user@buildserver nodejs-deploy]$ uname -a
Linux buildserver 4.4.30-32.54.amzn1.x86_64 #1 SMP Thu Nov 10 15:52:05 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

# uname -r
[ec2-user@buildserver nodejs-deploy]$ uname -r
4.4.30-32.54.amzn1.x86_64

ip

鸟哥网络基础概念

ip概念

# IP 位址的組成與分級
既然 IP 的組成是 32 bits 的數值,也就是由 32 個 0 與 1 組成的一連串數字!那麼當我們思考所有跟 IP 有關的參數時,你就應該要將該參數想成是 32 位元的資料喔! 不過,因為人類對於二進位實在是不怎麼熟悉,所以為了順應人們對於十進位的依賴性,因此,就將 32 bits 的 IP 分成四小段,每段含有 8 個 bits ,將 8 個 bits 計算成為十進位,並且每一段中間以小數點隔開,那就成了目前大家所熟悉的 IP 的書寫模樣了。如下所示:
IP 的表示式:
00000000.00000000.00000000.00000000   ==> 0.0.0.0
11111111.11111111.11111111.11111111   ==> 255.255.255.255

# Host_ID为 0 代表整个网段,为 1(那个字节的8个比特位都为1,即255) 代表广播地址

在同一個網段內,Net_ID 是不變的,而 Host_ID 則是不可重複,此外,Host_ID 在二進位的表示法當中,不可同時為 0 也不可同時為 1 ,因為全為 0 表示整個網段的位址 (Network IP),而全為 1 則表示為廣播的位址 (Broadcast IP)。例如上面的例子當中,192.168.0.0 (Host_ID 全部為 0)以及 192.168.0.255 (Host_ID 全部為 1) 不可用來作為網段內主機的 IP 設定,也就是說,這個網段內可用來設定主機的 IP 是由 192.168.0.1 到 192.168.0.254;

# 而192.168.0.0 ~ 192.168.0.255 是 Class C 的網域,前3位为 Net_ID,第4位为 Host_ID。而 Net_ID 可以是1位(Class A),所以 0.0.0.0 代表的整个网段。InterNIC 將整個 IP 網段分為五種等級, 每種等級的範圍主要與 IP 那 32 bits 數值的前面幾個位元有關,基本定義如下:

以二進位說明 Network 第一個數字的定義:
Class A : 0xxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx  ==> NetI_D 的開頭是 0
          |--net--|---------host------------|
Class B : 10xxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx  ==> NetI_D 的開頭是 10
          |------net-------|------host------|
Class C : 110xxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx  ==> NetI_D 的開頭是 110
          |-----------net-----------|-host--|
Class D : 1110xxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx  ==> NetI_D 的開頭是 1110
Class E : 1111xxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx  ==> NetI_D 的開頭是 1111

五種分級在十進位的表示:
Class A :   0.xx.xx.xx ~ 127.xx.xx.xx
Class B : 128.xx.xx.xx ~ 191.xx.xx.xx
Class C : 192.xx.xx.xx ~ 223.xx.xx.xx
Class D : 224.xx.xx.xx ~ 239.xx.xx.xx
Class E : 240.xx.xx.xx ~ 255.xx.xx.xx
# 3class中 私有ip的约定范围
Class A:10.0.0.0    - 10.255.255.255
Class B:172.16.0.0  - 172.31.255.255
Class C:192.168.0.0 - 192.168.255.255

Class C 會將巷子定義到第三個數字 Class C 的網域號碼佔了 24 位元 netmask 也是 32 位元,在數值上,位於 Net_ID 的為 1 而 Host_ID 為 0,所以, Class C 的netmask为

Netmask  : 11111111.11111111.11111111.00000000  <== Netmask 二進位
         :   255   .  255   .  255   .   0      <== Netmask 十進位

gateway

不要把gateway和netmask(255.255.255.0等)搞混了, gateway的ip一般也是取正常ip(如192.168.0.254),如不取192.168.0.0(网段代表) 也不取 192.168.0.255(网段广播)

Gateway / Router :網關/路由器的功能就是在負責不同網域之間的封包轉遞 (IP Forwarding),由於路由器具有 IP Forwarding 的功能,並且具有管理路由的能力, 所以可以將來自不同網域之間的封包進行轉遞的功能。此外,你的主機與你主機設定的 Gateway 必定是在同一個網段內喔!
# 跳板机上执行 route -n后的结果为
[ec2-user@buildserver nodejs-deploy]$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.31.16.1     0.0.0.0         UG    0      0        0 eth0
169.254.169.254 0.0.0.0         255.255.255.255 UH    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 br-ee08d16c16d6
172.31.16.0     0.0.0.0         255.255.240.0   U     0      0        0 eth0

# 解释
说明这台机器上共有5个路由规则。Destination为目的地网域。Iface为要去到這個目的地要使用哪一個網路介面。如果我们传送的封包所在的Destination的那一行(如172.17.0.0)的Gateway为0.0.0.0,就表示就會直接以後面的網路介面來傳送出去,而不透過 Gateway 咯。
萬一我們要傳送的封包目的地 IP 不在路由規則裡面,那麼就會將封包傳送到『default0.0.0.0)』所在的那個路由規則去,也就是 172.31.16.1 那個 Gateway 喔!所以,幾乎每一部主機都會有一個 default gateway 來幫他們負責所有非網域內的封包轉遞!
其中169.254.169.254 0.0.0.0 的Flags为 H 代表該行路由為一部主機,而非一整個網域,而Netmask为255.255.255.255也表示它不属于某个网域。
172.17.0.0 172.18.0.0 172.31.16.0这三个Network属于不同的网域,他们的Gateway都是0.0.0.0

ifconfig

# 如何取得自己本機的網卡卡號 (MAC)
[ec2-user@buildserver nodejs-deploy]$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:C0:92:B8:EE:96
          inet addr:172.31.16.4  Bcast:172.31.31.255  Mask:255.255.240.0
          inet6 addr: fe80::c0:92ff:feb8:ee96/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1400  Metric:1
          RX packets:909004713 errors:0 dropped:0 overruns:0 frame:0
          TX packets:653796302 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:149243553778 (138.9 GiB)  TX bytes:2513766889421 (2.2 TiB)

进程process

并发

其实就是单核的能力并发http请求差不多这样,8vcpu的1000左右,4vcpu那就500,单核写死100就可以了。 /Users/liujunyang/work/xuetang/wechat-router/lib/pipes/consumer.js

单台服务器并发TCP连接数到底可以有多少 ?

子进程

segmentfault.com/q/101000001… node child_process.exec 打开一个exe,如何立刻得知命令结果而不是等该exe退出。unref

windows 上快速使用vim

git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim

node 杀其他进程

# 杀ppt进程
# 项目 /Users/liujunyang/work/xuetang/node-queue/lib/Consumer_download.js:119

/**
 * 杀ppt,杀完继续worker
 * windows 命令行 https://blog.csdn.net/qq_35923749/article/details/83786794
 * sed 命令 http://linux.vbird.org/linux_basic/0330regularex.php#basicre
 *
 * 1.tasklist 罗列windows进程
 * 2.grep POWERPNT 找到ppt进程 返回值形如(中间空格数量不稳定,160就是pid):"POWERPNT.EXE         160 RDP-Tcp#70         2    212,860 K"
 * 3.sed 把pid前面的字符去掉,得到 "160 RDP-Tcp#70         2    212,860 K"
 * 4.cut -d " " -f 1 得到pid 160
 * 5.taskkill -t -f -pid 强杀进程
 *
 */
Consumer.prototype.killppt = function () {
    console.log('ppt进程即将查杀', Date.now())
    var order = `tasklist | grep POWERPNT | sed 's/^POWERPNT\.EXE *//' | cut -d " " -f 1 | xargs taskkill -t -f -pid`;
    return child_process.exec(order, (error, stdout, stderr) => {
        if (error !== null) {
            // 有的话也是已经没有ppt进程
            console.log('ppt进程查杀失败: ' + error);
        } else {
            console.log('ppt进程已结束', Date.now(), stdout)
        }

        this.isPPTBroken = false
        return setTimeout(() => {this.worker()}, 3000);
    });
}

tmp目录

blog.csdn.net/u011068702/… 该目录下的文件,系统会自动定期清除,一般是30天

bash

curl -H "Content-Type:application/json" -X POST -d '{"loginid": 21, "expire_seconds": 592000}' https://gc.xuetangonline.com/wechat/wxapi/qrcode?key=rain

hostname

修改机器名字

# 查询
hostname 回车

# 修改机器名字
sudo hostname rain-dropx

grep

# The --exclude option takes globs that are matched against file names, not directories or full paths:

grep --exclude-dir="logs" -rn  wxc78670ec5e4ef4d1 .

grep --exclude="node-auth-access.log" -rn  wxc78670ec5e4ef4d1 .

grep --exclude="node-auth-*.log" -rn  wxc78670ec5e4ef4d1 .
# 找出当前文件夹中除了common_config和node_modules外的包含config.的行
grep -rn --exclude-dir=common_config --exclude-dir=node_modules  config\\. .

变量

变量的设定规则

等號兩邊不能直接接空白字元

變數內容若有空白字元可使用雙引號『"』或單引號『'』將變數內容結合起來,但雙引號內的特殊字元如 $等,可以保有原本的特性,如下所示:
『var="lang is $LANG"』則『echo $var』可得『lang is zh_TW.UTF-8』
單引號內的特殊字元則僅為一般字元 (純文字),如下所示:
『var='lang is $LANG'』則『echo $var』可得『lang is $LANG』

若該變數為擴增變數內容時,則可用 "$變數名稱" 或 ${變數} 累加內容,如下所示:
『PATH="$PATH":/home/bin』或『PATH=${PATH}:/home/bin』

split

#!/usr/bin/env bash

# 代码出处:wechat-router/scripts/user_split.sh

# 1.手动将运营传过来的csv文件改名为 users.csv
# 2.按 1万行分割 split -l 10000 users.csv slice
# 3.将拆分后的每个文件首行前面添加一行 users.csv 的首行,如: app_openid,user_id,name,role,因为这是 csv 文件的字段名
#    雷测试环境:
#       find ./ -name "slice*" | xargs sed -i '1i\app_openid,user_id,name,role'
#       // 单文件: sed -i '1i\app_openid,user_id,name,role' ./sliceab
#    在 mac 上执行 sed 需要hack处理
#       // 单文件: sed -i '' '1i\'$'\napp_openid,user_id,name,role\n' sliceab
# 4.将第一个文件 sliceaa 多余的首行去掉 sed -i '1d' sliceaa
#
echo -e "\033[32m 拆文件 \033[0m"
split -l 10000 users.csv slice

echo -e "\033[32m 记得修改文件数量 FILE_COUNT: $(ls | grep slice |wc -l) \033[0m"

# 变量赋值时,等号两边不能有空格
firstline=$(head -n 1 users.csv)
echo -e "\033[32m 获取第一行的字段信息: $firstline \033[0m"

echo -e "\033[32m 将 $firstline 拆入到每个拆开的文件的第一行 \033[0m"
# sed 中使用变量的话,首先要用双引号,其次要用下面的双斜杠\\,否则 \$ 就成为将 $ 转义掉了
find ./ -name "slice*" | xargs sed -i "1i\\${firstline}"

echo -e "\033[32m 将第一个文件 sliceaa 多余的首行去掉 \033[0m"
sed -i '1d' sliceaa

nslookup

iterm

# 命令行快速移动
iterm里面 按 option +点击 即可快速移动光标(在pointer里面设置的),但是如果输入很长,发生了折行,可以先点到当前行的边上,然后按箭头挪行,然后继续使用 option+点击
ctrl +w 删除一个单词
ctrl +a 移动到头部
ctrl +e 移动到尾部
ctrl +y 粘贴之前剪切的内容
# tig
h 帮助页面
d 全屏当前diff
空格 向下翻一页
ctrl+d 向下翻一页
ctrl+u 向上翻半页

# rsync
rsync -av -e ssh lib/drop.js node@ykt03:~/thunder/drop_pipe/lib/drop.js

tar

鸟哥文档

部署jsmhc jsmhd
先在jsmha 打包所有项目 (z表示用gzip的方式压缩)
tar -zc -f node-projects.tar.gz node-projects/

传到本机
scp  deploy@jsmha:~/node-projects.tar.gz ./

在传到新机器
scp ./node-projects.tar.gz  ec2-user@jsmhc:~/

在新机器解压 
tar -zxf node-projects.tar.gz

因为common_config的软连接不同,需要重新软连一下
jsmhc 启动完毕后
在pm2 save  pm2 resurrect的方式启动

ps top free netstat 鸟哥

ps -l # 仅观察自己的bash相关的程序,可以看到ppid(-l Long format)
ps aux # 观察系统所有程序
ps axjf # 列出類似程序樹的程序顯示

kill -l # 列出目前 kill 能夠使用的訊號 (signal) 有哪些
kill -9 pid # 立刻強制刪除一個工作

ctrl z # 將『目前』的工作丟到背景中『暫停』
jobs -l # 觀察目前的背景工作狀態,同時列出 PID 的號碼
fg # 將背景工作拿到前景來處理,預設取出那個 + 的工作

top # M 内存排列;P cpu排列;q 退出
top -p pid # 僅觀察單一程序
pstree -Aup # 找程序之間的相關性.如果子程序掛點或者是老是砍不掉子程序時,該如何找到父程序

free -m # 以M为单位查看内存(或者-h也可以,自动取单位)
free -h -c 4 -s 1 # 以适合人类的方式显示4次状态,每次间隔1秒(-c 必须在 -s 的前面)

uname -a # 查閱系統與核心相關資訊
Linux study.centos.vbird 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 
以上面範例一的狀態來說,我的 Linux 主機使用的核心名稱為 Linux,而主機名稱為 study.centos.vbird,核心的版本為 3.10.0-229.el7.x86_64 ,該核心版本建立的日期為 2015-3-6,適用的硬體平台為 x86_64 以上等級的硬體平台喔

netstat # 追蹤網路或插槽檔 -t tcp; -u udp; -n 以数字显示地址(Show numerical addresses instead of trying to determine symbolic host, port or user names.); -p 显示pid; -l 列出目前正在網路監聽 (listen) 的服務;

可以通过 netstat 查看到某个端口的服务的pid,然后通过pstree -Aup 查看整个进程依赖,之后通过搜索看该pid所处的环节。

系統信息

# 查看cpu信息
# 总核数 = 物理CPU个数 X 每颗物理CPU的核数 
# 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数

# 查看物理CPU个数
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l

# 查看每个物理CPU中core的个数(即核数)
cat /proc/cpuinfo| grep "cpu cores"| uniq

# 查看逻辑CPU的个数
cat /proc/cpuinfo| grep "processor"| wc -l

脚本

正则

# 判断一行中有没有"-1"
re="-1"
while read line
do
    if [[ "$line" =~ $re ]]; then :
        echo "has -1"
    else
        arr=($line)
#        num=$((arr[0]+arr[1]+arr[2]))
        echo $line
    fi
done < bbc

预设变数

链接

/path/to/scriptname  opt1  opt2  opt3  opt4 
       $0             $1    $2    $3    $4
       
$# :代表後接的參數『個數』,以上表為例這裡顯示為『 4 』;
"$@" :代表『 "$1" "$2" "$3" "$4" 』之意,每個變數是獨立的(用雙引號括起來);
"$*" :代表『 "$1c$2c$3c$4" 』,其中 c 為分隔字元,預設為空白鍵, 所以本例中代表『 "$1 $2 $3 $4" 』之意。
那個 "$@""$*" 基本上還是有所不同啦!不過,一般使用情況下可以直接記憶 "$@" 即可!

环境变数

链接 链接2

$$
Shell本身的PIDProcessID)
$!
Shell最后运行的后台ProcessPID
$?
最后运行的命令的结束代码(返回值)
$-
使用Set命令设定的Flag一览
$*
所有参数列表。如"$*"用「"」括起来的情况、以"$1 $2$n"的形式输出所有参数。
$@
所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2""$n" 的形式输出所有参数。
$#
添加到Shell的参数个数
$0
Shell本身的文件名
$1$n
添加到Shell的各参数值。$1是第1参数、$2是第2参数…。

& 工作控制 (job control):將指令變成背景下工作 !表示上一个指令的返回值

trap

链接 trap命令用于指定在接收到信号后将要采取的动作,trap "exit 1" HUP INT PIPE QUIT TERM 表示当shell收到HUP INT PIPE QUIT TERM这几个命令时,当前执行的程序会读取参数“exit 1”,并将它作为命令执行。

/Users/liujunyang/work/xuetang/deploy/deploy/run.sh:27

asyncRun() {
    "$@" &
    pid="$!"

     my_exit()
    {
        cd ${WORK_DIR}
        pm2 sendSignal SIGTERM $APP_NAME
        while [ $(pm2 list | grep ${APP_NAME} |wc -l) != 0 ]; do  # 等到 pm2 list 数目为 0 时退出 docker
            echo -e "\033[32m等待退出。。。。\033[0m" && sleep 0.1
        done
    }


    trap "my_exit;exit;" SIGINT SIGTERM

    while kill -0 $pid; do
        wait
    done


}
asyncRun pm2-docker pm2_${APP_NAME}.yml

kill wait

代码位置:/Users/liujunyang/work/xuetang/deploy/deploy/run.sh:29

kill -0 pid 不发送任何信号,但是系统会进行错误检查。 所以经常用来检查一个进程是否存在,存在则echo $?返回0;不存在返回1

# 进程pid如果存在,直接不执行,执行done之后的代码。进程pid如果不存在,就wait,直到所有相关子进程执行结束,然后再检查,然后结束。
while kill -0 $pid; do
        wait
    done

wait是用来阻塞当前进程的执行,直至指定的子进程执行结束后,才继续执行。使用wait可以在bash脚本“多进程”执行模式下,起到一些特殊控制的作用。

链接 下面的目录是概念一层层递进的关系。

树、数组等,就是规则,用这种规则去存储、查询数据会有相应的性能。

树的基本概念

树是一种非线性的数据结构,相对于线性的数据结构(链表、数组)而言,树的平均运行时间更短(往往与树相关的排序时间复杂度都不会高)

二叉树

二叉树的意思就是说:每个节点不能多于有两个儿子

二叉查找树

链接 二叉树中还有一种特殊的二叉树:二叉查找树(binary search tree)

定义:当前根节点的左边全部比根节点小,当前根节点的右边全部比根节点大。 明眼人可以看出,这对我们来找一个数是非常方便快捷的

自平衡二叉查找树(AVL树 人名)

链接 AVL 是人名] 在最好的情况下,二叉排序树的查找效率比较高,是 O(logn),其访问性能近似于折半查找;

但最差时候会是 O(n),比如插入的元素是有序的,生成的二叉排序树就是一个链表,这种情况下,需要遍历全部元素才行 因此就要用到平衡二叉树(AVL 树)了。

平衡二叉树的提出就是为了保证树不至于太倾斜,尽量保证两边平衡。因此它的定义如下:

平衡二叉树要么是一棵空树

要么保证左右子树的高度之差不大于 1

子树也必须是一颗平衡二叉树

也就是说,树的两个左子树的高度差别不会太大。 平衡二叉树在添加和删除时需要进行旋转保持整个树的平衡。

B树

链接 什么是B树

B树就是 B-树 B-Tree,中间不是减号。

B树每个节点的关键字数为子树个数减一(子树个数 k 介于树的阶 M 和它的二分之一)。

# 和平衡二叉树相同的:
同时每个节点左子树的数据比当前节点都小、右子树的数据都比当前节点的数据大

# 和平衡二叉树不同有这么几点:
平衡二叉树节点最多有两个子树,而 B 树每个节点可以有多个子树,M 阶 B 树表示该树每个节点最多有 M 个子树
平衡二叉树每个节点只有一个数据和两个指向孩子的指针,而 B 树每个中间节点有 k-1 个关键字(可以理解为数据)和 k 个子树( **k 介于阶数 M 和 M/2 之间,M/2 向上取整)
B 树的所有叶子节点都在同一层,并且叶子节点只有关键字,指向孩子的指针为 null

更好的说法应该是B树每个节点有k个子树和k-1个关键字,先定的k,关键字始终是比子树树少1,因为B树是用的范围查询(左边小,右边大)。这点和B+树是不同的(也是左小右大,只是包含边界)。

前面介绍了二叉树的功能及特点,知道了它们在进行查找数据时可以提高效率,但需要注意的是,这是指在内存中进行查找。如果有海量的数据,不可能一次性读取到内存中,这时候就要考虑的是,如何在磁盘中快速找到需要的数据。

今天这篇文章中要介绍的“B 树、B+ 树”,他们的使用场景是:查找磁盘中的大量数据。

B+树

B+树是B树的变形版,查询效率更高。 什么是B+树

# 一棵 B+ 树需要满足以下条件:
节点的子树数和关键字数相同(B 树是关键字数比子树数少一)
节点的关键字表示的是子树中的最大数,在子树中同样含有这个数据
叶子节点包含了全部数据,同时符合左小右大的顺序