Shell常用命令大全之入门篇
本文为shell的一个系列教程,分为入门篇、命令篇、实战篇
教程里尽量减少复杂的文字描述,不求全,但求精,以实例为主,目标是让读者快速上手shell。
以下为本教程的第一部分《入门篇》,欢迎读者拍砖及找BUG,后续会根据反馈进行修改及补充。
CSDN的Markdown生成的目录显示符号有一点小问题,大家以详细内容中的标题为准。
- 入门篇
- 第一招 HelloWorld
- 第一式echo
- 第二招 判断
- 第一式if
- 判断原理
- 第二式test 和
- 文件测试
- 字符串比较
- 整数比较
- 第三式
- 第一式if
- 第三招循环
- 第一式for
- 第二式whileuntil
- 第四招变量
- 第一式整数
- 整数的运算
- 第二式字符串
- 替换
- 截取子串
- 通配删除
- 第三式数组
- 普通数组
- 关联数组
- 第四式将命令执行结果存入变量
- 与
- 换行符处理
- 第一式整数
- 第五招重定向
- 标准输入流标准输出流标准错误流
- 重定向方式一览表
- 第一式重定向标准输出流stdout
- 第二式重定向标准错误流stderr
- 第三式重定向标准输入流stdin
- 第六招管道
- 第一式管道的基本功能
- 第二式管道与whileread组合
- 第三式管道与xargs组合
- 第七招通配
- shell通配的原理
- 通配符一览表
- 第一式
- 第二式
- 第三式
- 第四式
- 第一招 HelloWorld
入门篇
第一招 HelloWorld
第一式:echo
echo "Hello World"
echo -n "Hello World" # 不带换行
echo -e '\e[0;33;1mHello\e[0m World' # 带颜色的玩法 echo -e '\e[0;33;4mHello\e[0m World' # 带颜色+下划线 echo -e '\e[0;33;5mHello\e[0m World' # 带颜色+闪烁
格式为 \e[背景色;前景色;高亮格式m,请阅读详细文档后使用正确的姿势进行装逼。
第二招 判断
第一式:if
if true
then
echo "Hello World"
else
echo "Bug"
fi
if false
then
echo "Hello World"
elif true
then
echo "Bug"
else
echo "Bee"
fi判断原理
if、elif会执行它后面跟着的命令,然后看返回值是否为0,如果为0则执行then下面的语句块,否则执行else下面的语句块。
[linuxidc@Ubuntu:~]$ true [linuxidc@ubuntu:~]$ echo $? 0 [linuxidc@ubuntu:~]$ false [linuxidc@ubuntu:~]$ echo $? 1
注:
true、false事实上也为一个命令,true的返回码必为0,false的返回码必为1$?为shell内置变量,用于存放上一个命令的返回码
第二式:test、[ ] 和 [[ ]]
test、[ ]、[[ ]]实际上都是shell中的命令,执行之后会返回1或0,而这几个命令与if相结合可以达到我们所需要的许多判断功能,例如测试字符串是否为空的三种写法:
s=""
if [ -z ${s} ]
then
echo "empty"
fi
if [[ -z ${s} ]]
then
echo "empty"
fi
if test -z ${s}
then
echo "empty"
fi事实上,if后的[ ]、[[ ]]、test命令都是可以单独执行的,而根据if的判断原理,后续执行哪个分支也是由[ ]、[[ ]]、test的返回值来决定的,以下是单独执行它们的效果:
[linuxidc@ubuntu:~]$ s=""
[linuxidc@ubuntu:~]$ [ -z "${s}" ]
[linuxidc@ubuntu:~]$ echo $?
0
[linuxidc@ubuntu:~]$ s="abc"
[linuxidc@ubuntu:~]$ test -z "${s}"
[linuxidc@ubuntu:~]$ echo $?
1
[linuxidc@ubuntu:~]$ s="123"
[linuxidc@ubuntu:~]$ [[ 100 -lt ${s} ]]
[linuxidc@ubuntu:~]$ echo $?
0在性能方面[ ]和test性能基本相同,[[ ]]性能是最高的,为前两者的5倍左右(以-d运算符测试),所以建议尽量使用[[ ]]提高脚本性能。
文件测试
| 运算符 | 描述 | 示例 |
|---|---|---|
| -e filename | 如果 filename 存在,则为真 | [ -e /var/log/syslog ] |
| -d filename | 如果 filename 为目录,则为真 | [ -d /tmp/mydir ] |
| -f filename | 如果 filename 为常规文件,则为真 | [ -f /usr/bin/grep ] |
| -L filename | 如果 filename 为符号链接,则为真 | [ -L /usr/bin/grep ] |
| -r filename | 如果 filename 可读,则为真 | [ -r /var/log/syslog ] |
| -w filename | 如果 filename 可写,则为真 | [ -w /var/mytmp.txt ] |
| -x filename | 如果 filename 可执行,则为真 | [ -L /usr/bin/grep ] |
| filename1 -nt filename2 | 如果 filename1 比 filename2 新,则为真 | [ /tmp/install/etc/services -nt /etc/services ] |
| filename1 -ot filename2 | 如果 filename1 比 filename2 旧,则为真 | [ /boot/bzImage -ot arch/i386/boot/bzImage ] |
字符串比较
| 运算符 | 描述 | 示例 |
|---|---|---|
| -z string | 如果 string 长度为零,则为真 | [ -z "${myvar}" ] |
| -n string | 如果 string 长度非零,则为真 | [ -n "${myvar}" ] |
| string1 = string2 | 如果 string1 与 string2 相同,则为真 | [ "${myvar}" = "abc" ] |
| string1 != string2 | 如果 string1 与 string2 不同,则为真 | [ "${myvar}" != "abc" ] |
| string1 < string | 如果 string1 小于 string2,则为真 | [ "${myvar}" \< "abc" ][[ "${myvar}" < "abc" ]] |
| string1 > string | 如果 string1 大于 string2,则为真 | [ "${myvar}" \> "abc" ][[ "${myvar}" > "abc" ]] |
注意:
- 在字符串两边加上”“防止出错
<和>是字符串比较,不要错用成整数比较- 如果是在
[ ]中使用<和>,需要将它们写成\<和\>
整数比较
| 运算符 | 描述 | 示例 |
|---|---|---|
| num1 -eq num2 | 等于 | [ 3 -eq $mynum ] |
| num1 -ne num2 | 不等于 | [ 3 -ne $mynum ] |
| num1 -lt num2 | 小于 | [ 3 -lt $mynum ] |
| num1 -le num2 | 小于或等于 | [ 3 -le $mynum ] |
| num1 -ge num2 | 大于或等于 | [ 3 -ge $mynum ] |
第三式:&&、||
&&可以用来对两个判断语句求与 |
|---|
if [ -n "abc" ] && [ -n "aa" ] |
if [[ -n "abc" ]] && [[ -n "aa" ]] |
if test -n "abc" && test -n "aa" |
if [[ -n "abc" && -n "aa" ]] |
注:只有[[ ]]才允许把&&写在里面
||可以用来对两个判断语句求或 |
|---|
if [ -n "abc" ] || [ -n "aa" ] |
if [[ -n "abc" ]] || [[ -n "aa" ]] |
if test -n "abc" || test -n "aa" |
if [[ -n "abc" || -n "aa" ]] |
小技巧
&&、||还可以用来拼接命令,达到按前一个命令成功与否来决定是否执行后一个命令的效果
cd /data && ls # 当`cd /data`返回0(即成功)时才执行后面的`ls` cd /data || cd /root # 当`cd /data`返回非0(即失败)时才执行后面的`cd /root`
第三招:循环
第一式:for
for i in {1..100}
do
echo ${i}
done注:
{1..100}属于通配的一种写法,展开会是1 2 3 ... 100(1~100以空格隔开)这样的字串。例如
for i in 1 2 3;这样的语句,for会将1、2、3依次赋值于i进行循环,而对于通配的情况,for则会将通配展开后将里面的每一项依次赋值于i进行循环。
for i in `seq 100`
do
echo ${i}
done
for i in `seq 1 2 100`
do
echo ${i}
done注:
seq本身为一个命令,用于输出数字组成的序列,如seq 100会生成并输出1 2 3 ... 100(1~100以换行符隔开)这样的序列,而seq 1 2 100则会生成并输出1 3 5 ... 99(以1开始,2为公差的等差数列中小于100的项,以换行符隔开)。- 反引号(`)之间的命令会被执行,其输出结果会转换成一个变量,故上面的
for in会依次取出seq的执行结果赋值于i进行循环。
for ((i = 0; i < 100; i++))
do
echo ${i}
done
for ((i = 0; i < 100; i+= 2))
do
echo ${i}
done注:
以上与C语言式的for循环语法基本相同,区别在于双重括号:(( ))
第二式:while、until
i=0
while [[ ${i} -lt 100 ]]
do
echo ${i}
((i++))
donei=0
until [[ ${i} -ge 100 ]]
do
echo ${i}
((i++))
done注:
while和until的判断原理与if是类似的,它会执行并它后面跟着的命令,不同点在于:
while是后面语句返回值为0,则执行循环中的语句块,否则跳出循环;until则是后面语句返回值非0,则执行循环中的语句块,否则跳出循环。