Home shell常用命令手册
Post
Cancel

shell常用命令手册

trick command

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 获取当前文件绝对路径
curPath=$(cd `dirname $0`; pwd)

# 判断当前用户是否为root用户
user=$(env | grep USER | cut -d "=" -f 2)

# 字符串A包含字符串B
if [[ "$A" =~ "$B" ]]

# ${var##*/}字符串截取

# 使用正则提取子串
echo here365test | sed 's/.*ere\([0-9]*\).*/\1/g'  # 输出365
# 其中s表示替换,\1表示用第一个括号里面的内容替换整个字符串, sed支持*,不支持?、+,不能用\d之类,正则支持有限。

# 变量默认值 如果a有变量就是a的值,否则是1 同理${a:--1}才是-1
${a:-1} 

# 判断变量是否存在, 如果变量var存在就输出var,否则输出"",和${var:-}的区别在于,var不存在前者不会报错,后者会报错
if [ -z/-n ${var:+} ]; then
fi

# 文件按行读出
常规可能使用for line in `cat xx`,但是这样的问题在于如果一行中有空格则会变成多个变量进入循环,所以请使用
cat xx | while read line
do
  echo ${line}
done

其实read非常实用,除了它本身的功能,最好用的就是循环赋值了,上面也展示了,当然还可以为多个变量同时赋值,例如awk获取了两个字段
read v1 v2 <<< `cat xx | awk '{print $1, $2}'`

空格会将一行拆分成多行正是因为系统默认分隔符IFS(内部字段分隔符internal field separator),其默认是空格,\t\n。所以如果我们修改IFS也能达到按行拆分的效果。好处在于“我在go调用cmd命令时read命令不起作用!”
OLD_IFS="$IFS"
IFS=$'\n'
xxxxx
IFS=$OLD_IFS
其中首尾两行用于恢复默认IFS,如果不需要也可以不写

字符串分割使用read也非常方便, 可以通过IFS自定义分隔符,其中IFS在while scope内部定义,也不会影响到全局的IFS
-r 会对\n等转义字符保留\,-a表示作为数组读入
while IFS="$delimiter" read -ra readLines; do
	for line in "${readLines[@]}"; do
	  xxx
	done
done <<< "$string"

# 遍历文件夹下所有文件,但是带有空格,和上面的一样都是空格在捣乱,这里可以使用和上面一样的方法,也可以使用先替换再替换回来的方法
symbol="觉d怼e部z科k恁" # 选择一个绝对不可能出现的短语
for file in `ls xx | sed 's/ /'"${symbol}"'/g'`
do
  realFileName=`sed 's/'"${symbol}"'/ /g' <<<$file` # realFileName就是包含空格的真正文件名
done


# 嵌套变量可使用eval读出, 用于传入一个环境变量本身的名字,然后获取环境变量的真实值
a="cat" 
b="a"  # 传入b
eval tmp=`echo '$'$b` # eval会多次扫描,第一次->echo $a,第二次->cat
echo $tmp # 结果就是cat
关于更多eval:https://www.cnblogs.com/huzhiwei/archive/2012/03/14/2395956.html


关于shell的并发和管道控制 https://blog.csdn.net/dubendi/article/details/78931979

对于自动化或者测试来说,我们在执行程序时可能会需要键盘输入,使用expect可以很方便地通过判断程序输出来控制输入,实现自动化。
https://www.jellythink.com/archives/373

shell 编程

  • 数组
    bash支持一维数组(不支持多维数组),并且没有限定数组的大小。
    1
    2
    3
    4
    5
    6
    7
    
    array_name=(value0 value1 value2 value3)
    # 获得数组所有元素
    ${array_name[@]}${array_name[*]}
    # 获得数组长度
    ${#array_name[@]}
    # 取得数组单个元素的长度
    lengthn=${#array_name[n]}
    
  • 循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 步进
{1..10}$(seq 1 10)
{1..10..2}$(seq 1 2 10)  # 步长为2

# 其中所有;do都改成下行写do不要;
# for 循环
for 变量名 in 列表;do 
  循环体
done

# whlie 循环
while CONDITION; do
  循环体
done
  • 参数
1
2
3
4
5
6
7
8
9
10
11
12
$0   Shell本身的文件名
$1   Shell的第一个位置参数,一直到$9;当n>=10时,需要使用${n}来获取参数
$#   传递到脚本的参数个数
$*   以一个单字符串显示所有向脚本传递的参数
$$   脚本运行的当前进程ID号
$!   后台运行的最后一个进程的ID号
$@$*相同,但是使用时加引号,并在引号中返回每个参数。
$-   显示Shell使用的当前选项,与set命令功能相同。
$?   显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

最后一个参数不能使用${$#},需要使用${@: -1},并且中间的空格是必须的,或者是${!#}。
但是如果没有参数,那么第一种是空串,而第二种则是相当于$0,也就是脚本名,所以推荐使用第一种。
  • 比较
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 字符串比较(前六个也可用于数字比较)
-eq   等于
-ne   不等于
-gt   大于
-lt   小于
-le   小于等于
-ge   大于等于
-z    空串
=     两个字符相等
!=    两个字符不等
-n    非空串
=~    左边字符串包含右边字符串

# 文档比较 
-e filename存在
-d filename为目录
-f filename常规文档
-L filename为符号链接
-r filename可读
-w filename可写
-x filename可执行

bash编程常用技巧

the-art-of-command-line

bash严格模式,将这两行放在开头

1
2
3
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

bash script执行加锁

1
2
3
4
5
if ! (set -o noclobber ; echo > /tmp/global.lock) ; then
    exit 1  # the global.lock already exists
fi

# ... remainder of script ...

shell check

冒号的妙用

在linux中冒号(:)常用来做路径的分隔符(PATH)。其实,冒号(:)在Bash中也是一个内建命令,它啥也不做,是个空命令。
常见作用如下

1、占位符
比如在编写脚本的过程中,某些语法结构需要多个部分组成,但开始阶段并没有想好或完成相应的代码,这时就可以用:来做占位符,否则执行时就会报错。

1
2
3
4
5
if [ "today" == "2011-08-29" ]; then  
    :  
else  
    :  
fi  

2、写注释,但是一般不这样写,就不举例了

3、清空文件
:>filename

4、缺省值
echo ${var:-DEFAULT}

https://www.cnblogs.com/ChinaGo/p/9910747.html

awk

awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息

特殊要点:
$0 表示整个当前行
$n 每行第n个字段
NR 每行的记录号,多文件记录递增

分隔符:

1
2
3
awk -F":" '{print $1}'  filename                    以:为分隔符输出每行分割后第一项  
awk -F: '{print $1; print $2}'   filename           将每一行的前二个字段,分行输出  
awk  -F: '{print $1,$3,$6}' OFS="\t" filename       输出字段1,3,6,以制表符作为分隔符  

判断语句:

1
2
3
4
5
6
awk -F: '{if($1~/mail/) {print $1} else {print $2}}' filename  
awk -F: 'NR==5{print}'  filename        显示第5行  
其中匹配方法有:  
//纯字符匹配   !//纯字符不匹配   ~//字段值匹配    !~//字段值不匹配   ~/a1|a2/字段值匹配a1或a2   
条件表达式:  
==   !=   >   >=  > <  

需要使用shell中的变量只需要使用-v参数,例如shell中有一个参数num=2
awk -v inner_num=${num} 'NR==inner_num{print $1}',但是需要注意,如果num中包含/符号则会报错,需要用双引号括起来

sed

https://www.cnblogs.com/maxincai/p/5146338.html

jq

详细文档可以看https://stedolan.github.io/jq/manual/

说一个用例,获取一个数组中每个元素的id,并生成bash中的array

1
2
3
4
5
6
# @sh => 输入经过转义,适合在 POSIX shell 的命令行中使用。如果输入是数组,则输出将是一系列以空格分隔的字符串。
# tr -d 删除多余的引号,这个视情况而定,字符串可以不删除引号

array=($(yabai -m query --displays | jq '.[].index | @sh' | tr -d \'\"))

This post is licensed under CC BY 4.0 by the author.

mpv播放器介绍

crontab和notify-send不可共用问题