;
- bash在解析字符的时候,对待“;”跟看见回车是一样的行为
[ ... ]
- 其实就是个shell test命令的另一种写法
- 命令加参数要用空格分隔, 所以
[ ... ]
需要加空格
[[ ... ]]
- a Bash extension , bash, zsh, yash support it
bash
built-in, and cannot be used in a#!/bin/sh
script- benefits
==
and!=
perform pattern matching, so the right-hand side can be a glob pattern$ [[ abc = *bc ]] ; echo $? 0
=~
performs regular expression matching. Captured groups are stored in theBASH_REMATCH
array.- boolean operators
&&
and||
- no word splitting, so it's not strictly necessary to quote your variables.
- drawback:
- your script is now bash-specific.
(...)
- indicate a subshell
- What's inside is a list of commands (just like outside parentheses)
- These commands are executed in a separate subprocess,
- so any redirection, assignment, etc. performed inside the parentheses has NO EFFECT outside the parentheses.
- With a leading dollar sign,
$(…)
is a command substitution - the output from the command is used as part of the command line
((...))
- double parentheses surround an arithmetic instruction
- mostly used for assignments and in conditionals. This only exists in ksh/bash/zsh, not in plain sh.
- The same syntax is used in arithmetic expressions
$((…))
, which expand to the integer value of the expression.
- list
- 若干shell命令组成的序列, 使用
管道
,;
,&
,&&
,||
这些符号串联起来
- 若干shell命令组成的序列, 使用
- 一切皆表达式
- shell在执行任何东西(注意是任何东西,不仅是命令)的时候都会有一个 return status
- 0-255
- 0为真(true)
- 非0为假(false)
echo $?
来查看上一个执行命令的返回值
!
- 对表达式求反
- bash 通配符
?
单个字符*
任意数量的字符[...]
类似正则表达式中的[]
$
变量$0
获得自己执行命令的进程名称$n
第n个参数$#
参数个数$*
,$@
holds list of all arguments passed to the script- There is no difference if you do NOT put
$*
or$@
in quotes. - But if you put them inside quotes (which you should, as a general good practice),
- then
$@
will pass your parameters as separate parameters, - whereas
$*
will just pass all params as a single parameter.
- then
- https://stackoverflow.com/questions/22589032/what-is-the-difference-between-and
- There is no difference if you do NOT put
$?
上一个命令的返回值- 所以上述所有取值都可以写成
${x}
的方式
if list; then list; elif list; then list; ... else list; fi
等价于
if list
then
list
elif list
then
list
...
else
list
fi
- if 后面跟的就是个shell命令
- return status 作为 condition (0 is true)
if cd mydir; then ...
- if语法中 后面最常用的命令就是
[]
if [ $ret -eq 0 ] ...
- 等价于
if test $ret -eq 0 ...
while list-1
do
list-2
done
until list-1
do
list-2
done
while list-1; do list-2; done
until list-1; do list-2; done
case EXPRESSION in
PATTERN_1)
STATEMENTS
;;
PATTERN_2)
STATEMENTS
;;
PATTERN_N)
STATEMENTS
;;
*)
STATEMENTS
;;
esac
for VARIABLE in LIST
do
command1
command2
done
- while
LIST
could befor VARIABLE in 1 2 3 4 5 .. N
for VARIABLE in file1 file2 file3
for OUTPUT in $(Linux-Or-Unix-Command-Here)
for i in {1..5}
- bash3.0+
C-sytle syntax
for (( initializer; condition; step ))
do
shell_COMMANDS
done
e.g.
for (( c=1; c<=5; c++ ))
do
echo "Welcome $c times"
done
select i in a b c d
do
echo $i
done
提供给了我们一个构建交互式菜单程序的方式
$ ./select.sh
1) a
2) b
3) c
4) d
#?
#!/bin/bash
select i in a b c d
do
case $i in
a)
echo "Your choice is a"
;;
b)
echo "Your choice is b"
;;
c)
echo "Your choice is c"
;;
d)
echo "Your choice is d"
;;
*)
echo "Wrong choice! exit!"
exit
;;
esac
done
内建命令,并不是关键字
- source, or
.
- 读取文件的内容,并在当前bash环境下将其内容当命令执行
- read
- 从 标准输入读取输字符串到一个变量中
read -p "Login: " username
- 读取到数组中
read -a test
- 从 标准输入读取输字符串到一个变量中
- mapfile
- 将一个文本文件直接变成一个数组,每行作为数组的一个元素
- readarray
- 同上
- 如果内建命令放到管道环境中执行,那么bash会给它创建一个subshell进行处理。于是创建的数组实际上与父进程没有关系
- printf
- 进行格式化输出
- getopts
- 命令行参数处理
- 优先级
- alias
- keyword
- function
- built-in commands (cd, pwd, etc...)
- hash (用hash命令可以查看 hash情况)
- external commands
- you can use
type
to check whether a command is built-in, external, alias, or etc.$ type pwd pwd is a shell builtin $ type docker docker is /usr/local/bin/docker $ type myfind myfind is a shell function from /Users/xxx/.myProfile
- 脚本的退出
- built-in command
exit
, 人为指定退出的返回码是多少 - 如果不使用exit 指定,使用最后执行命令的返回码
- built-in command
- 调试
-v
可视模式, 执行bash程序的时候将要执行的内容也打印出来-x
跟踪模式(xtrace), 跟踪各种语法的调用,并打印出每个命令的输出结果-n
检查bash的语法错误, 不会真正执行bash脚本-e
脚本命令执行错误的时候直接退出
env
- 查看当前bash已经定义的环境变量
aaa=100
- 这是个一般变量,不能被子进程继承
export
- 可以将一个一般变量转成环境变量
export aaa
- 进程信息
- HOSTNAME
- HOSTTYPE
- OLDPWD / PWD
- HOME
- SHELL
- BASHPID
- UID / EUID
- GROUPS 用户组
- PPID 父进程PID
- RANDOM
- 得到一个0-32767的随机数
echo $RANDOM 24746
- 得到一个0-32767的随机数
- ulimit
- 查看和设置bash环境中的资源限制
ulimit -a
- shell在产生一个新进程后,新进程的前三个文件描述符都默认指向三个相关文件
- 0 stdin
- 1 stdout
- 2 stderr
- stdin redirection
- 可以读取其他终端输入
cat < /dev/pts/3
- stdout redirection
>
- stderr redirection
2>
- 常见用法
- 只看报错信息
xxx > /dev/null
- 只看正确输出
xxx 2> /dev/null
- 所有输出都不看
xxx &> /dev/null
- or
xxx >& /dev/null
- short-cut to
> /dev/null 2>&1
, but not support by Dash, POSIX Shells, and Ksh, e.g./bin/sh
- 将标准报错输出,重定向到和标准输出相同的地方
xxx 2>&1
&1
表示 引用 fd 1
- 从描述符3读取
3<
- 只看报错信息
- To understand "redirecting to /dev/null"
- redirect both stdin and stderr to /dev/null
CMD 1> /dev/null 2> /dev/null
- Enhancement 1: You can replace
1>
with just>
. This is because 1 is the default stdout and you can ignore mentioning defaults.CMD > /dev/null 2> /dev/null
- Enhancement 2: You can replace the 2nd file redirect (
> /dev/null
) with a file descriptor duplication (>& 1
). This is because /dev/null is already pointed to by stdout 1.CMD > /dev/null 2>& 1
- Enhancement 3: This is such a common operation, that many shells have a shortened form of this as a single
&>
operator.CMD &> /dev/null
- redirect both stdin and stderr to /dev/null
|
command1 | command2
- 将command1的stdout跟command2的stdin 通过管道(pipe)连接起来
|&
command1 |& command2
- 将command1 stdout 和 stderr 都跟command2的和stdin连接起来
command1 2>&1 | command2
的简写方式
- 定义数组
declare -a array
- 元素赋值
array[0] = 1000
- 取值
${array[0]}
${array[*]}
(get all)${#array[*]}
(数组长度)
- 定义一个关键数组
declare -A array
$ {a,b,c,d}{1,2,3,4}
a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4 d1 d2 d3 d4
$ {a,c}.conf
a.conf c.conf
-
:-
A or 1000${aaa:-1000}
-
:=
A or A=1000${aaa:=1000}
-
Slice
${aaa:10:5}
- aaa[10:15],
[start:length]
- aaa[10:15],
${aaa:10}
- aaa[10:]
${aaa: -5}
- aaa[:-5] 注意负号 前面的空格
${#aaa}
- 变量值的长度
${aaa#pattern}
- remove pattern
- 从左往右, 从头match 到第一个
^pattern
,删除pattern,取其后面的字串
${aaa##pattern}
- greedy version
- keey base path
$ aaa="/Volumes/WORK/WORK/test" $ echo ${aaa##*/} test
- get file extension
${aaa##*.}
${aaa%pattern}
- also remove pattern, except it apply to the back of variable.
$ FILE="xcache-1.3.0.tar.gz" $ echo "${FILE%.tar.gz}" xcache-1.3.0
- remove file extension
${aaa%.*}
- also remove pattern, except it apply to the back of variable.
${aaa%%pattern}
- greedy version
-
字符串替换
${aaa/pattern/string}
- 将
pattern
匹配到的第一个字符串替换成string
- 将
${aaa//pattern/string}
- 全局替换
-
算数扩展
((...))
$ a=1 $ ((a++)) $ echo $a 2
- 支持 整数运算/位运算/关系运算/三元运算
- 内建命令let
let i=i**2
(())
的另一种写法
- uniq : report or filter out repeated lines
- uniq 多 伴随着 sort 命令同时出现, 因为 uniq 只能去掉 相邻的重复line
- 虽然
sort -u
自己就可以去掉重复, 但 uniq 有这更多的功能 uniq -c
打印重复的次数5 chocolate 4 mint 1 ranbow 2 rocky
uniq -d
- display only repeated lines
chocolate mint rocky
uniq -u
- display non-dup lines
ranbow
- combo...
$ sort favFlavors.txt | uniq -c | sort -nr 5 chocolate 4 mint 2 rocky 1 ranbow
$ ls *.{json,py}
$ echo Day{1..7}
Day1 Day2 Day3 Day4 Day5 Day6 Day7
$ su testuser
To simulate a full login
$ su -[l] testuser
$ ls -l
drwxr-xr-x 5 mebusy staff 160 Aug 1 2022 go
drwxr-xr-x
- the 1st character could be
d
: a directory-
: a filel
: a symbolic link
- the following 9 characters are
rwx
permssions forowner
,group
,others
(any user)
syntax:
chmod mode file
- who
- u : user
- g : group
- o : others
- a : all
- what
-
: remove permission+
: grants permission=
: set a permission and remove others
- which
- r : read permission
- w : write permission
- x : execute permission
examples:
- add write permission to group
chmod g+w file.txt
- remove write permission from all
chmod a-w file.txt # or chmod -w file.txt
- prevent others to access this file
chmod o-rwx file.txt