0%

shell技巧介绍介绍

​ Shell 脚本在我们日常开发和学习都有举足轻重的地位,比如看一些开源项目,比如项目中的各式各样的脚本,对于促进生产力工具有很大帮助!而且shell最大的好处就是依赖比较小,直接可以运行!

1、命令小技巧

1、-x 命令进行跟踪调试执行

1
2
3
4
5
6
7
8
9
#!/bin/sh

num1=10
num2=20
if (($num1 <= $num2)); then
echo num1 lesser equal num2
else
echo num1 greater num2
fi

执行:

1
2
3
4
5
6
➜  note git:(master) ✗ sh -x /Users/fanhaodong/Desktop/project/test.sh
+ num1=10
+ num2=20
+ (( 10 <= 20 ))
+ echo num1 lesser equal num2
num1 lesser equal num2

2、-c 命令 (执行命令参数)

1
2
3
4
5
6
7
➜  note git:(master) ✗ sh -c << EOF "
dquote> echo hello world
dquote> echo hello world2
dquote> "
heredoc> EOF
hello world
hello world2
  1. 这种经常会在网上下载一个脚本然后直接执行,可以 sh -c "curl xxxx.sh"

3、使用set变量

一般就是 set -ex ,或者执行的时候 bash -ex

1
2
3
4
5
6
7
8
9
10
#!/bin/sh

# -v Print shell input lines as they are read.
# -x Print commands and their arguments as they are executed.
# -e Exit immediately if a command exits with a non-zero status.
set -ex

echo "hello world"

exit 1

执行

1
2
3
4
5
6
➜  makefile git:(master) ✗ sh ./main.sh
+ echo 'hello world'
hello world
+ exit 1
➜ makefile git:(master) ✗ echo $?
1

帮助可以看: sh -c "help set"

2、语法小技巧

1、引用变量

一般推荐正确用法是,变量使用 "" 双引号引用,其次就是变量使用 ${}进行引用!very good!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 使用 ${} 引用变量,拒绝歧义
➜ ~ data="hello" ;echo $dataa

➜ ~ data="hello" ;echo ${data}a
helloa

# 字符串用 "" 引用
➜ ~ data="hello " ;echo "${data}a"
hello a
➜ ~ data=hello ;echo "${data}a"
helloa

# 单引号不会进行变量赋值 (注意)
➜ ~ data=hello ;echo '${data}a'
${data}a

2、 $( cmd ) 和 `cmd` 执行命令

1
2
3
4
➜  ~ echo $(uname)
Darwin
➜ ~ echo `uname`
Darwin

3、 cat [>>|>] [file] << EOF .... EOF 写入文件

如果重定向的操作符是<<-,那么分界符(EOF)所在行的开头部分的制表符(Tab)都将被去除。这可以解决由于脚本中的自然缩进产生的制表符。

1
2
3
4
5
6
7
8
9
10
11
12
➜  test cat > glide.yaml << EOF
heredoc> name: tom
heredoc> age: 10
heredoc> hobby:
heredoc> - football
heredoc> EOF

➜ test cat glide.yaml
name: tom
age: 10
hobby:
- football

4、管道符 和 xargs

1. 管道符

管道符作用就是把上一个命令的标准输出作为下一个命令个标准输入

1
2
➜  echo "hello wrold" | python -c 'import sys; print(sys.stdin.read())'
hello wrold

2. xargs

1 .xargs的作用就是把上个命令的标准输出 作为 下一个命令的参数

1
2
➜  echo "hello wrold" | xargs python -c 'import sys; print(sys.argv)'
['-c', 'hello', 'wrold']
  1. 如果想替换分隔符号需要输入参数 -d, 同时你想打印所执行的命令 -t
1
2
3
4
5
6
7
➜  ~ echo "hello:wrold" | xargs -t -d ':' python -c 'import sys; print(sys.argv)'
python -c 'import sys; print(sys.argv)' hello 'wrold'$'\n'
['-c', 'hello', 'wrold\n']

# 上面带\n的原因是echo默认换行,需要
➜ ~ echo -e "hello:wrold\c" | xargs -d ':' python -c 'import sys; print(sys.argv)'
['-c', 'hello', 'wrold']
  1. xargs 是并行执行的,可以通过如下测试**, -P等于0表示不限制进程数**,默认是1, -n等于1表示参数按每一个进行拆分

​ 这个命令相当棒,就是可以并行执行!

1
2
3
4
5
➜  echo "hello world" | xargs -P0 -n1  sh -c 'echo "start $$"; sleep 5s; echo "end $$"'
start 21377
start 21378
end 21377
end 21378
  1. -I,可以替换命令行参数
1
2
3
4
5
➜  ~ echo "hello wrold" | xargs echo
hello wrold

➜ ~ echo "hello wrold" | xargs -I {} echo {}
hello wrold

5、特殊变量

  • $0: 当前脚本的文件名
  • $n : 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
  • $#: 传递给脚本或函数的参数个数。
  • $*: 传递给脚本或函数的所有参数。
  • $@: **传递给脚本或函数的所有参数(推荐使用这个)**,当使用 "" 双引号引用是 $*会变成字符串而不是数组
  • $?: 上个命令的退出状态,或函数的返回值。一般情况下,大部分命令执行成功会返回 0,失败返回 1。
  • $$: 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。

6、[[]][] 标准 以及基本语法规范

具体规范: https://github.com/koalaman/shellcheck/wiki/SC2039

1
2
3
4
5
#!/bin/sh
name=""
if [[ -z $name ]]; then
echo "is zero"
fi

执行后发现

image-20210408220400561

7、/bin/sh 与 /bin/bash 的区别

/bin/sh 与 /bin/bash 的区别

3、获取命令结果 $(cmd)

有两种写法,一种是 $()这个并不是所有的shell都支持,但是比较直观, 另外一种是 "``" (它可是适用更多的平台)

1
2
3
4
5
#!/bin/sh

echo `ls -a /Users/fanhaodong/note`

echo $(ls -a /Users/fanhaodong/note)

输出:

1
2
. .. .DS_Store 1714.jpg docker-rocketmq-cluster gridea-home hexo-home note pdf vuepress-starter
. .. .DS_Store 1714.jpg docker-rocketmq-cluster gridea-home hexo-home note pdf vuepress-starter

4、输入输出重定向 2>&1

使用

程序中经常有,标准输出,但是还有错误输出,因此需要合并到一个流中

其实Go的程序中正执行脚本的时候可以指定,标准输出和错误输出

1
2
3
command := exec.Command(shell, "-c", cmd)
command.Stdout = os.Stdout
command.Stderr = os.Stderr

使用的时候:

  • 默认为标准输出重定向,与 1> 相同
  • 2>&1 意思是把 标准错误输出 重定向到 标准输出.
  • &>file 意思是把标准输出和标准错误输出 都重定向到文件file中

例如:

command >out.file 2>&1 &

command >out.file是将command的标准输出重定向到out.file文件,即输出内容不打印到屏幕上,而是输出到out.file文件中。2>&1 是将标准出错重定向到标准输出,这里的标准输出已经重定向到了out.file文件,即将标准出错也输出到out.file文件中。最后一个&,是让该命令在后台执行。

参考

https://www.cnblogs.com/caolisong/archive/2007/04/25/726896.html

5、If语句

​ if 其实就是test 命令

1、格式

  1. 换行写
1
2
3
4
5
6
7
if [ condition ]; then
# body
elif [ condition ]; then
# body
else
# body
fi

2)非换行写

1
if [ -f "/Users/fanhaodong/note/note/Makefile1" ]; then  echo 111 ; echo 222 ;elif [ -f "/Users/fanhaodong/note/note/README.md" ]; then  echo 333 ; echo 4444 ; else  echo 555 ; echo 666 ; fi

2、结果获取/判断

结果输出0 ,表示为真,可以通过$? 来获取结果

3、例如调试条件

1
2
3
➜  note git:(master) ✗ test "abc"!="def"
➜ note git:(master) ✗ echo $?
0

4、测试文件是否存在

  • 如果你要判断一个文件是否存在,只需要 -e 即可,输出0 表示文件存在 (不在判断类型的时候推荐使用这个)
  • 如果你要判断一个文件是否为文件夹,并且判断是否存在,只需要 -d 即可
  • 如果你要判断一个文件是否为常规文件 ,并且判断是否存在,只需要-f 即可
  • -L filename 如果 filename为符号链接,则为真
1
2
3
4
5
[root@019066c0cd63 ~]# ls -al
lrwxrwxrwx 1 root root 5 Mar 1 09:49 c.txt -> a.txt
[root@019066c0cd63 ~]# [ -L "./c.txt" ]
[root@019066c0cd63 ~]# echo $?
0
  • -r filename 如果 filename可读,则为真
  • -w filename 如果 filename可写,则为真
  • -x filename 如果 filename可执行,则为真
  • -s filename 如果文件长度不为0,则为真
  • -h filename 如果文件是软链接,则为真
1
2
3
4
5
6
➜  note git:(master) ✗ [ -f "/Users/fanhaodong/note/note/Makefile" ]
➜ note git:(master) ✗ echo $?
0
➜ note git:(master) ✗ [ -f "/Users/fanhaodong/note/note/Makefile1" ]
➜ note git:(master) ✗ echo $?
1

5、字符串操作

​ 字符串推荐加 "" 进行定义

  1. 判断字符串是否为空 -z (zero)么
1
2
3
4
5
6
7
#!/bin/sh

str=""
if [ -z "${str}" ]; then
echo str is empty
fi
# str is empty

2)判断两个字符串是否相同

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh

str1="str"
str2="str2"

if [ "$str1" = "$str2" ]; then
echo str1 is equal str2
else
echo str1 is not equal str2
fi

# str1 is not equal str2

4、测试一个命令是否存在 command -v $#

1
2
3
4
5
6
7
8
#!/bin/sh
cmd=go
if [ `command -v $cmd` ]; then
echo $cmd command is exists
else
echo $cmd command not exists
fi
# go command is exists

5、获取字符串长度 ${#var}

1
2
3
4
5
6
7
8
#!/bin/sh
str="hello "
str1=hello
echo str 的长度是 ${#str}
echo str1 的长度是 ${#str1}

#str 的长度是 8
#str1 的长度是 5

6、数字比较

  • -eq 等于
  • -ne 不等于
  • -gt 大于
  • -ge 大于等于
  • -lt 小于
  • -le 小于等于
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh

num1=10
num2=20
if (($num1 <= $num2)); then
echo num1 lesser equal num2
fi

if [ $num1 -le $num2 ]; then
echo num1 lesser equal num2
fi

# num1 lesser equal num2
# num1 lesser equal num2

7、shell脚本中if判断’-a’ - ‘-z’含义

https://blog.csdn.net/tootsy_you/article/details/95597376

image-20210527103147909

image-20210527103211720

image-20210527103224576

6、for循环

1、for <item> in <items> ; do <script1>; <script2>;done

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

for item in {1..5}; do echo "$item"; done

[Running] /bin/bash "/Users/fanhaodong/note/note/Linux/shell/file.sh"
1
2
3
4
5

2、for((x=0; x<10; x++));do <script1>; <script2>; done

1
for((x=0; x<10; x++));do echo "$x" ;done
本人坚持原创技术分享,如果你觉得文章对您有用,请随意打赏! 如果有需要咨询的请发送到我的邮箱!