extra-shell-notes

自学收集的一些有用的 shell 奇淫妙技。

unset

1
2
unset 变量名
unset .f 函数名

.f 前后有空格。用于删除定义了的变量与函数。

包含文件

1
2
3
. filePath

source filePath

. 后面有一空格。

注释

shell 没有块注释,可以使用一对花括号将需要注释的内容包起来,定义成一个函数,但是后面不使用改函数,从而曲线救国。

字符串

获取字符串长度

1
2
string="abcd"
echo ${#string} #输出 4

提取子字符串

1
2
string="alibaba is a great company"
echo ${string:1:4} #输出liba

查找子字符串

1
2
string="alibaba is a great company"
echo `expr index "$string" is` # 查找 is 在变量中的位置

数组

之前一直不会用,get 到技能,这里记录一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

NAME[0]="Zara"
NAME[1]="Qadir"
NAME[2]="Mahnaz"
NAME[3]="Ayan"
NAME[4]="Daisy"
echo "First Index: ${NAME[0]}"
echo "Second Index: ${NAME[*]}"
# * 与 @ 效果一样,显示全部

# 打印
for i in ${NAME[@]}
do
echo ${NAME[$i]}
done

# 批量修改
for i in ${NAME[@]}
do
NAME[$i]=`expr $i + 5 `
echo ${NAME[$i]}
done

其他赋值方式

1
2
3
array=(var1 var2)
array=([0]=var1 [1]=var2)
array[0]=var1

计算数组元素个数

1
2
3
${#array[@]}
# 或者
${#array[*]}

遍历

1
2
3
4
5
6
7
for var in ${array[@]}; do
echo $var
done

for ((i = 0; i < ${#array[@]}; i++)); do
echo ${array[$i]}
done

参考内容1, 内容2.

无限循环

1
2
3
4
5
6
7
8
9
10
while :
do
somescripts;
done

# 或者
while true
do
somescripts;
done

取最后一行

获取最后一行数据。

法一,

1
echo $varibles | tail -1

法二,

1
echo $varibles | awk 'END{print}'

法三,

1
echo $varibles | sed -n '$p'

其他,

1
2
3
4
sed '$!N;$!D'
# 获取最后两行
# 一样的效果
awk '{b=a"\n"$0;a=$0}END{print b}'

参考资料

不让别名生效

.bashrc 或者 .profile 里面定义 alias 可以简化命令输入,但有时想用非别名命令,可以在前面加一个 \\ ,如下

1
\grep something filename

ps 命令

ps 命令的参数有:

参数 作用
-a 显示所有进程(包括其他用户的)
-u 用户以及其他信息
-x 显示没有控制终端的进程

特别地,ps aux 这种短格式不加减号(-)也是合法的。

1
2
3
pidof sshd # 显示程序 PID
kill 3459 # 停止PID对应程序
killall httpd # 终止程序所有进程

有用的小命令

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
last # 系统登录记录

history # 执行命令历史

# 几个全称
su:Swith user # 切换用户,切换到root用户
cat:Concatenate # 串联
uname:Unix name # 系统名称
df:Disk free # 空余硬盘
du:Disk usage # 硬盘使用率
tar:Tape archive # 解压文件
pwdprint working Directory # 打印工作目录
grep:global regular expression print
sudo:Superuser do
chown:Change owner # 改变所有者
chgrp:Change group # 改变用户组
chmod:Change mode # 改变模式
# 路径全称
/bin = BINaries
/dev = DEVices
/etc = Editable Text Configuration # 配置文件
/opt = Optional application software packages
/lib = LIBrary
/tmp = TeMPorary
/usr = Unix Shared Resources
/var = VARiable # 储存各种变化
/proc = PROCesses
/sbin = Superuser BINaries
1
2
3
4
5
6
7
8
more filename # 一页一页看
head -n 20 filename # 看头,默认 10行
head - 20 filename # 简洁的写法
tail ... # 和head类似,显示 尾部
tr [原始字符] [目标字符] # 替换,例子如下
cat filename | tr [a-z] [A-Z] # 全部大写
wc -lwc # 统计字等
stat filename # 文件详情
1
2
3
# cut 按 列 提取文本
tail -20 ~/.bash_history |cut -d' ' -f2
# -d 设置分割, -法显示列
1
2
3
# diff 比较文件差异
diff -c fileA.sh fileB.sh
# -c 详情, --brief 给出判断结果

touch 修改已经存在文件的信息。

参数 作用
-a 修改“读取时间”(atime)
-m 修改“修改时间”(mtime)
-d 上面两者同时修改
1
touch -d '2018-05-15 01:22:23' filemname

历史命令

!数字 用于重复执行某次命令。
history 查看历史命令。
mkdir -p /a/b/c 递归迭代创建文件夹。

sed

  • 多个匹配:
1
2
3
sed '1,3s/my/your/g; 3,$s/This/That/g' my.txt
# 等价于
sed -e '1,3s/my/your/g' -e '3,$s/This/That/g' my.txt
  • 使用&来当做被匹配的变量
1
sed 's/my/[&]/g' my.txt
  • 圆括号

使用圆括号匹配的示例:(圆括号括起来的正则表达式所匹配的字符串会可以当成变量来使用,sed中使用的是\1,\2…)

1
2
3
4
5
$ sed 's/This is my \([^,&]*\),.*is \(.*\)/\1:\2/g' my.txt
cat:betty
dog:frank
fish:george
goat:adam

上面这个例子中的正则表达式有点复杂,解开如下(去掉转义字符):

正则为:This is my (\[^,&]\*),.\*is (.*)
匹配为:This is my (cat),……….is (betty)

然后:\1就是cat,\2就是betty.

参考内容或者这里

变量

1
2
3
4
5
6
7
8
9
10
11
12
# 变量    意义
$0 脚本文件名
$1/$2 第N(>1)个参数
$# 参数个数
[email protected] 所有参数(数组)
$* 所有参数(字符串)
$- 当前脚本执行时的附加参数,比如`-x`
$_ 最近的参数(或者当前脚本执行的目录)
$IFS 输入字段分隔符,一般是空格
$! 最近的后台执行的命令
$$ 当前脚本的 pid
$? 脚本执行后的返回值

当脚本内需要向另一个脚本或函数传递所有参数时:
应使用"[email protected]"而不是$*或者"$*""[email protected]"会把所有参数都按原样传递过去,而$*遇到有空格的参数会分割成多个,"$*"则是把所有参数变成一个参数(字符串)传进去。

vim 编辑后无权限

在底栏模式下:
:w !sudo tee %
然后按提示输入密码 确认:[O]K, (L)oad File: 输入 L 会重新载入,丢失所有操作记录,推荐直接使用 O.
解析: 此命令是把当前文件(即%)作为stdin传给sudo tee命令来执行.

不用 tee 的实现方式:

1
2
3
4
:w !sudo sh -c "cat > %"

# 当然可以在 vimrc 里面加入下一个映射.
cmap w!! w !sudo sh -c "cat > %"

:r !pwd:r !ls 将执行结果复制到 vim 中.

vim 替换中,%的意义是代表整个文件,而执行外部命令时则是文件名.

可以详见 此处.

查看归档或压缩文件内容

无需解压,查看 归档文件包含的内容。

  1. vim
    命令模式下直接使用 vim 可以查看归档文件内容。

  2. tar -tf 文件路径
    此法在 man tar 有说。

  3. rar unrar zip unzip

1
2
3
4
5
6
7
rar v 文件.rar
# 字幕 L
unrar l 文件.rar

zip -sf 文件.zip

unzip -l 文件.zip
  1. 其他

zipinfo zcat zless
以及 less

bash

  1. 转换小写

    1
    2
    3
    4
    5
    6
    var='ExampleAAA'
    var="${var,,}"
    # var : exampleaaa

    # 只小写第一个
    var="${var,}"

    bash 4+

  2. 转换大写

    1
    2
    3
    4
    5
    6
    var='ExampleAAA'
    var="${varR^^}"
    # var : EXAMPLEAAA

    # 只大写第一个
    var="${var^}"

    bash 4+

  3. 大小写转换

    1
    2
    3
    4
    5
    6
    var='ExampleAAA'
    var="${var~~}"
    # var : eXAMPLEaaa

    # 只改变第一个大小写
    var="${var~}"

    bash 4+

    作为对比:常用的还有 ${var#[regex]} 从前向后删第一个匹配的 [regex]${var##[regex]} 从前向后删所有匹配的 [regex]# 换成% 表示掉头,从后向前。

  4. 冒号(:)作用,以及_
    通常情况使用 冒号 占位,和Python中的pass作用类似,除此之外还有替代临时变量作用

    1
    2
    3
    4
    5
    var='  test text   '
    : "${1#"${var%%[![:space:]]*}"}"
    : "${_%"${_##*[![:space:]]}"}"
    var="$_"
    # var='test text'

    可以看到临时变量存到_中。

  5. 字符串长度,使用

    1
    ${#var}

    其中var为变量。hexo踩过的坑

  6. 读取文件到变量,而不用cat

    1
    2
    file_data="$(< "file/path")"
    # 比使用 cat 速度更快!
  7. 使用变量访问变量

    1
    2
    3
    4
    5
    6
    7
    8
    cookie_tt='vbdbv45367'
    site='tt'
    # 法一
    echo "$(eval echo '$'"cookie_$site")"

    # 法二
    : cookie_$site
    echo ${!_}
  8. 使用变量命名另外一个变量

    1
    2
    3
    4
    var="world"
    declare "hello_$var=value"
    printf '%s\n' "$hello_world"
    # value
  9. 取变量第一行

    1
    2
    3
    4
    5
    var='111
    222
    333'
    "${var/$'\n'*/}"
    # var = 111
  10. 大括号范围

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 普通范围
    echo {1..10}

    # 小数
    echo 1.{1..6}

    # 嵌套
    echo {a..z}{1..10} # 260个

    # 零填充
    echo {01..100} # 001 002 ...

    # 改变步长
    echo {1..10..2} # 1 3 5 7 9

    # 字符串列表
    rm -rf ~/Downloads/{Movies,Music,ISOS}
  11. bash 的扩展匹配模式
    开启方法 shopt -s extglob,关闭shopt -u extglob
    -s means set-u means unsetshopt
    shopt 即是 Shell Optionextglob即是Extended Globbing

    1
    2
    3
    4
    # 例子
    var='123.720p.456'
    echo "${var/+(720p|1080p)}"
    # var 123..456

    其他还有
    ?(pattern-list) 匹配一个或者零个模式
    *(pattern-list) 匹配多个或者零个模式
    +(pattern-list) 匹配一个或者多个模式
    @(pattern-list) 匹配一个模式
    !(pattern-list) 匹配除了模式的其他模式

    除了路径匹配,放在测试里面也可以,此外,可以嵌套,不能使用{}
    参考文档-http://mywiki.wooledge.org
    参考文档-linuxjournal
    参考文档-gnu

待续……

ASCII值转换为字符

使用 awk

1
awk 'BEGIN{printf("%c",91)}'

使用 printf

1
2
printf \\x`printf "%x" 91`
# 先转 16 进制,再\x5b 转成 ASCII 字符。

字符转ascii值

1
2
3
printf "%d" \'A
# 或者
printf "%d" "'A"