自学收集的一些有用的 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 # 解压文件
pwd:print 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)个参数
$#        参数个数
$@        所有参数(数组)
$*        所有参数(字符串)
$-        当前脚本执行时的附加参数,比如`-x`
$_        最近的参数(或者当前脚本执行的目录)
$IFS      输入字段分隔符,一般是空格
$!        最近的后台执行的命令
$$        当前脚本的 pid
$?        脚本执行后的返回值

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

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为变量。{% post_link hexo-pit 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"