目录
1.终端打印
1.1 实战
- 使用不带引号的echo,不能再文本中使用分号,因为分号在bash中被用作命令定界符
- 变量替换在单引号中无效
- 双引号中打印特殊字符需要加转义字符:
echo "hello world\!"
- printf函数也可用于打印,类似于C语言
printf "s%" No
1.2 补充内容
- echo -n 忽略行尾的换行符
- echo -e 接收转义序列
ian@ian-virtual-machine:~$ echo "12\t3"
12\t3
ian@ian-virtual-machine:~$ echo -e "12\t3"
12 3
- 使用转义序列可以打印彩色输出
echo -e "\e[1;42m Green Backgroud \e[0m"
输出:
2. 玩转变量
2.1 进程环境变量
查看进程运行时的环境变量可以用这个命令:
cat /proc/$PID/environ
输出:
USER=ianLC_TIME=zh_CN.UTF-8TEXTDOMAIN=im-configXDG_SEAT=seat0XDG_SESSION_TYPE=x11SSH_AGENT_PID=1628SHLVL=0QT4_IM_MODULE=ximHOME=/home/ianDESKTOP_SESSION=ubuntuGTK_MODULES=gail:atk-bridgeGNOME_SHELL_SESSION_MODE=ubuntuLC_MONETARY=zh_CN.UTF-8DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/busIM_CONFIG_PHASE=2LOGNAME=ianGTK_IM_MODULE=ibusUSERNAME=ianXDG_SESSION_ID=2WINDOWPATH=2PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/binLC_ADDRESS=zh_CN.UTF-8XDG_RUNTIME_DIR=/run/user/1000DISPLAY=:0LANG=en_US.UTF-8XDG_CURRENT_DESKTOP=ubuntu:GNOMELC_TELEPHONE=zh_CN.UTF-8XDG_SESSION_DESKTOP=ubuntuXMODIFIERS=@im=ibusXAUTHORITY=/run/user/1000/gdm/XauthoritySSH_AUTH_SOCK=/run/user/1000/keyring/sshLC_NAME=zh_CN.UTF-8SHELL=/bin/bashQT_ACCESSIBILITY=1GDMSESSION=ubuntuLC_MEASUREMENT=zh_CN.UTF-8TEXTDOMAINDIR=/usr/share/locale/GPG_AGENT_INFO=/run/user/1000/gnupg/S.gpg-agent:0:1LC_IDENTIFICATION=zh_CN.UTF-8XDG_VTNR=2QT_IM_MODULE=ximPWD=/home/ianCLUTTER_IM_MODULE=ximXDG_DATA_DIRS=/usr/share/ubuntu:/usr/local/share:/usr/share:/var/lib/snapd/desktopXDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/etc/xdgLC_NUMERIC=zh_CN.UTF-8LC_PAPER=zh_CN.UTF-8GNOME_DESKTOP_SESSION_ID=this-is-deprecatedXDG_MENU_PREFIX=gnome-SESSION_MANAGER=local/ian-virtual-machine:@/tmp/.ICE-unix/1533,unix/ian-virtual-machine:/tmp/.ICE-unix/1533DESKTOP_AUTOSTART_ID=10692a68641ba1de1158631729595816000000015330000GIO_LAUNCHED_DESKTOP_FILE=/usr/share/applications/org.gnome.Shell.desktopGIO_LAUNCHED_DESKTOP_FILE_PID=1
2.2 常见变量使用
- 变量赋值方法:var=value, var = value的写法是错的
- 可以在printf或者echo的双引号中引用变量
- 单引号不会被扩展,会按照原样式显示
ian@ian-virtual-machine:~$ echo $a
1
ian@ian-virtual-machine:~$ echo '$a'
$a
2.3 补充内容
- 获取字符串长度:${#var}
ian@ian-virtual-machine:~$ echo ${#a}
1
- 识别当前使用shell:echo $0 或者 echo $SHELL
- 检测是否为超级用户:echo $UID,返回值为0则为root
- 修改bash提示符:设置PS1变量,例如,PS1="Ian>"
ian@ian-virtual-machine:~$ PS1="Ian>" Ian>
3. 使用函数添加环境变量
当需要经常安装软件,将路径加入到path中时,可以在bashr中添加一个添加路径的函数。
比如常见的加入path的命令为:
export PATH=/home/ian:$PATH
echo $PATH
/home/ian:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
加入bashrc的函数:
prepend() { [ -d "$2" ] && eval $1=\"$2':'\$$1\" && export $1; }
函数先检查第二个参数是否存在,如果存在
调用方法:
Ian>echo $PATH
/home/ian:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
Ian>prepend PATH /home/ian/Videos/
Ian>echo $PATH
/home/ian/Videos/:/home/ian:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
4. shell数学计算
可以使用let,(()),和[]执行基本的算术操作,expr和bc可以用于高级操作
- 基本运算
Ian>a=4 Ian>b=5 Ian>let result=a+b Ian>echo $result 9 Ian>result=$[ a + b ] Ian>echo $result 9 Ian>result=$(( a + 5)) Ian>echo $result 9 Ian>result=$(expr $a + 5) Ian>echo $result 9
不过,(())的写法在一些编程标准中是不允许的。基础运算只支持整数,不支持浮点数
-
bc可以进行浮点计算和高级函数的计算
Ian>echo "$a * 0.56"|bc 2.24 Ian>echo "sqrt(100)" |bc 10
5. 文件描述符及重定向
5.1 重定向默认描述符
系统保留的文件描述符:
- 0:stdin(标准输入)
- 1:stdout(标准输出)
- 2:stderr(标准错误)
5.2 如何重定向
使用>或者>>可以将标准输出重定向。
将标准错误重定向到文件:
Ian>ls + 2>a.log
Ian>cat a.log
ls: cannot access '+': No such file or directory
可以将标准输出和标准错误重定向到不同的文件:
ls + 2>a.log 1>b.log
将stderr转换成stdout之后重定向到一个文件:
ls + >a.log 2>&1
ls + >/dev/null 2>&1 #不输出任何信息
关于2>&1的含义可见
https://blog.csdn.net/sc9018181134/article/details/88432070
5.3 扩展方法
tee命令既可以将stdin中的数据重定向到文件,还可以提供一份重定向数据的副本作为后续的stdin(主要用于将标准输出重定向到文件中)
Ian>cat *.log *.lsodfj|tee a.out|cat -n
cat: '*.lsodfj': No such file or directory
1 ls: cannot access '+': No such file or directory
2 blog file
Ian>cat a.out
ls: cannot access '+': No such file or directory
blog file
当只需获取上一个命令的输出,而不需要输出到文件时,可以用tee -
Ian>echo who is this|tee -|cat -n
1 who is this
5.4 自定义文件描述符
文件描述符是一种用于访问文件的抽象指示器。具体解释:https://www.cnblogs.com/alan666/p/8311890.html
可以使用exec创建自定义的文件描述符;
Ian>touch input.txt
Ian>exec 3<input.txt
Ian>echo test input line >input.txt
Ian>cat <&3
test input line
如果需要再次读取就需要重新用exec分配。
6. 数组与关联数组
6.1 数组
- 定义数组
Ian>a=(1 2 3 4 5) Ian>b[1]=1
- 打印数组
Ian>echo ${a[*]}
1 2 3 4 5
Ian>echo ${b[*]}
5 1
Ian>echo ${a[0]}
1
6.2 关联数组(类似python中的字典)
- 定义关联数组,赋值关联数组,显示关联数组:
Ian>declare -A ass_a Ian>ass_a=([index1]=val1 [index2]=val2) Ian>ass_a[index3]=val3 Ian>echo ${ass_a[*]} val1 val2 val3 Ian>echo ${ass_a[index1]} val1
- 列出数组索引(key值)
Ian>echo ${!ass_a[*]}
index1 index2 index3
7. 使用别名
- alias创建,删除别名
Ian>alias hls='hadoop fs -ls' Ian>hls hadoop: command not found Ian>alias hls= Ian>hls Ian>
- 忽略别名使用,在命令之前加反斜杠'\'进行转义
Ian>alias hls1='hadoop fs -ls' Ian>\hls1 Command 'hls1' not found, did you mean: command 'hls' from deb hfsutils Try: sudo apt install <deb name>
8.日期和延时
- 读取,设置日期和时间:
Ian>date #获取日期
Thu Apr 9 21:15:35 CST 2020
Ian>date +%s #获取时间戳
1586438156
Ian>date --date "Thu Apr 9 21:15:35 CST 2020" +%s #将日期转换为时间戳
1586438135
Ian>date --date "Thu Apr 9 21:15:35 CST 2020" +%A #将日期按照星期打印
Thursday
- 格式串+可以作为date的参数,按照相应格式打印出日期,比如:
Ian>date +%A Thursday Ian>date "+%d %B %Y" 09 April 2020
-
日期格式列表如下:
日期:
%a : 星期几 (Sun..Sat)
%A : 星期几 (Sunday..Saturday)
%b : 月份 (Jan..Dec)
%B : 月份 (January..December)
%c : 直接显示日期和时间
%d : 日 (01..31)
%D : 直接显示日期 (mm/dd/yy)
%h : 同 %b
%j : 一年中的第几天 (001..366)
%m : 月份 (01..12)
%U : 一年中的第几周 (00..53) (以 Sunday 为一周的第一天的情形)
%w : 一周中的第几天 (0..6)
%W : 一年中的第几周 (00..53) (以 Monday 为一周的第一天的情形)
%x : 直接显示日期 (mm/dd/yy)
%y : 年份的最后两位数字 (00.99)
%Y : 完整年份 (0000..9999)时间:
% : 印出冒号
% %n : 下一行
%t : 跳格
%H : 小时(00..23)
%I : 小时(01..12)
%k : 小时(0..23)
%l : 小时(1..12)
%M : 分钟(00..59)
%p : 显示本地 AM 或 PM
%r : 直接显示时间 (12 小时制,格式为 hh:mm:ss [AP]M)
%s : 从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数 %S : 秒(00..61)
%T : 直接显示时间 (24 小时制)
%X : 相当于 %H:%M:%S
%Z : 显示时区
9. 调试脚本
- bash -x
bash -x命令可以打印出所执行的每一行命令及当前的状态。例如新建一个脚本:
#!/bin/bash
#script.sh
for i in 1 2 3;
do
echo $i
done
echo "done"
使用bash -x 命令:
Ian>bash -x script.sh
+ for i in 1 2 3
+ echo 1
1
+ for i in 1 2 3
+ echo 2
2
+ for i in 1 2 3
+ echo 3
3
+ echo done
done
- set -x和set +x
这两个命令可以设置在脚本的中间,只调试部分脚本(但是在Bash4.1.10后就不好使了):
修改script脚本:
#!/bin/bash
for i in 1 2 3;
do
set -x
echo $i
set +x
done
echo "done script"
输出:
Ian>bash script.sh
+ echo 1
1
+ set +x
+ echo 2
2
+ set +x
+ echo 3
3
+ set +x
done script
- 自定义显示调试信息:调用_DEBUG参数。修改脚本如下:
#!/bin/bash #script.sh function DEBUG() { [ "_DEBUG" == "on" ] && $@ || echo "debug" } for i in 1 2 3; do DEBUG echo $i done echo "done script"
调用:
Ian>bash script.sh debug debug debug done script
- 使用shebang调试:可将#!/bin/bash修改成为#!/bin/bash -xv
10. 函数和参数
- 定义函数
#!/bin/bash function fname1() { echo 1; } fname2() { echo 2; } fname3() { echo $1; } fname1 fname2 fname3 3
输出:
Ian>bash func.sh 1 2 3
- 导出函数:可以像环境变量一样导出函数。
export -f fname1
在原先的脚本中加入一行,然后source脚本,就可以调用函数:
Ian>source func.sh
1
2
3
Ian>fname1
1
- 读取命令返回值:$?
Ian>ls func.sh script.sh Ian>echo $? 0
11.管道:将命令序列的 输出读入变量
- 管道使用
ls | cat -n > out.txt
将ls的结果传入给cat -n
- 获取管道相连的命令序列的输出:$(cmd)
Ian>a=`ls | cat -n`
Ian>echo $a
1 func.sh 2 out.txt 3 script.sh
Ian>b=$(ls | cat -n)
Ian>echo $b
1 func.sh 2 out.txt 3 script.sh
- 定义一个子进程
命令在子进程执行,对当前任务没有任何影响:
#脚本
#!/bin/bash
pwd
(cd /home; pwd; ls)
pwd
#调用
Ian>sh prp.sh
/home/ian/test
/home
ian
/home/ian/test
12. read命令
read用于从键盘或者标准输入中读取文本。
- 从输入中读取n个字符:read -n 2 var
Ian>vim prp.sh
Ian>read -n 2 var
hiIan>echo $var
hi
- 无回显方式读取:read -s
- 显示提示信息读取:read -p "input:" var
- 特定时限内读取:read -t 10 var
- 用特殊的定界符作为输入行的结束:read -d ":" var
Ian>read -d ":" var
fdashfhas
fnaihfo
fjap'ja:Ian>echo $var
fdashfhas fnaihfo fjap'ja
13. 运行命令直至成功
- 定义一个repeat函数
repeat()
{
while true;
do
$@ && return
done
}
函数定义了一个while循环,如果传入函数返回为true,则返回,否则一直执行.
也可以用":"代替true
14.字段分隔符和迭代器
- 内部字段分隔符(IFS)设置当前文本的分隔符(默认为空格)。
Ian>echo $IFS
Ian>data="1,2,3"
Ian>for item in $data;do echo item:$item; done
item:1,2,3
Ian>IFS=,
Ian>for item in $data;do echo item:$item; done
item:1
item:2
item:3
- shell中生成数字或者字母列表
Ian>echo {1..3}
1 2 3
Ian>echo {a..e}
a b c d e
15. 比较与测试
- if 可以用于测试:
Ian>if true; then echo 1; fi
1
Ian>if false; then echo 1; elif true; then echo 2; else echo 3; fi
2
- 算数比较
注意在[]与操作符之间需要有一个空格,不然会报错
Ian>if [ $var -eq 0 ]; then echo 0; else echo 1; fi
0
-gt:大于
-lt:小于
-ge:大于等于
-le:小于等于
-a:逻辑与
-o:逻辑或
- 文件系统相关测试
-e filename 如果 filename存在,则为真
-d filename 如果 filename为目录,则为真
-f filename 如果 filename为常规文件,则为真
-L filename 如果 filename为符号链接,则为真
-r filename 如果 filename可读,则为真
-w filename 如果 filename可写,则为真
-x filename 如果 filename可执行,则为真
-s filename 如果文件长度不为0,则为真
-h filename 如果文件是软链接,则为真
- 字符串比较
[[ $str1 == $str2 ]]
>,=,!=,-z(空字符串),-n(非空字符串)
- 逻辑运算
&&,||