贡献者: addis
echo "..."
先输出来看看,而不是真的执行。看看变量展开是否和预期的一致(就像 make 一样)。
.sh
的文本文件,也可以没有。
./name.sh 参数1 参数2
也可以用 source /path/name.sh 参数1 参数2
(source
也可以简写成 .
。sh
shell 中只能用后者。), 前者在一个新的 shell process 中运行然后退出(环境变量之类的改动在退出会消失), 后者在当前的 shell process 运行, 相当于直接把文件中的内容复制粘贴到命令行执行.
;
隔开两个命令,第一个失败了第二个仍然会运行,但 &&
隔开则不会(这个其实是逻辑与算符)。
&&
后面可以直接换行,不需要加 \
>
把 shell 中的 stdout 导入文件.
#!
指定运行使用的 shell,如 #!/bin/bash
exit
结束 script,exit 0
声明运行成功
#
注释
var=xxx
,等号两边不能有空格。$var
或者 ${var}
获取它的值。例如 abc$var
或者 abc${var}def
。后者的花括号不能省略。
${var:2:5}
可以获取第 3 个字符开始的 5 个字符。
${var/旧文字/新文字}
可以对变量的字符串进行替换
${var:-"默认字符串"}
如果 var
未定义或为空,则输出 默认字符串
。
var
以 字符串
结束,${var%字符串}
移除最后的 字符串
var
以 字符串
开始,${var#字符串}
移除最前面的 字符串
varname=myvar
,那么 ${!varname}
相当于 ${myvar}
。如果 varname
是第一个参数,那么就用 ${!1}
$(命令)
或者 `命令`
相当于把 命令
的输出展开到当前位置,如 echo `pwd -P`
。
bins="123 234"
exec 文件名.sh
执行另一个脚本。
1>&2
,例如 echo bar 1>&2
。
./文件名.sh > 123.log
只会把 stdout 导入文件,而不包含 stderr。还要在后面加上 2>&1
。
"path/to/other_script.sh"
(待验证)
/bin/bash -c "命令"
命令 "abc def"
或者 命令 'abc def'
中,abc def
是一个参数,作为字符串传给 main()
函数的 argv[1]
,不包含引号。如果不加引号,abc
和 def
就分别是 argv[1]
和 argv[2]
。
"..."
中的 $变量
会展开,但是 '...'
中不会
'...'
就是绝对的 string literal,里面不会发生任何转义
'...'
中 escape 单引号,不能直接做到,可以用 'it'\''s here.'
其中三部分分别是 'it'
,\'
,'s here.'
。
echo 'abc\'def'gh'
会输出 abc\defgh
main()
,那么就 escape:\"
或者 \'
\
可以用 \\
来 escape
$var
、${var}
等展开。
命令 | 命令2
使用 pipe 把一个命令在 stdout 的输出作为另一个命令的 stdin 输入。特别注意 命令2
是在 subshell 执行的。如果在该 subshell 执行多个命令,可以用 命令 | { 命令2 ; 命令3 }
例如 echo 123 | { read line; echo "The line is: $line"; }
又例如 printf "123\n234\n" | while read line; do echo "The line is: $line"; done
中 while
可以看成一个命令。
echo 123;
if [ $? -ne 0 ]; then # 判断 exit status
...
fi
# 判断路径是否存在(感叹号后面一定要有空格)
if ! [ -d "$repo" ]; then
echo "directory not found!" 1>&2
fi
# 判断文件是否存在且不是文件夹或者特殊文件
if ! [ -f "$fname" ]; then
echo "file not found!" 1>&2
fi
# 判断相等
if [ $i -eq 3 ]
...
elif [ $i -ne 3 ]
...
fi
if
的简写如 [ -e 文件 ] && mv 文件 新文件
。例子:for file in file1 file2 file3; do [ -e "$file" ] && mv "$file" destination_directory done
-f, -d
,还有 -z
(判断字符串是否为空),-n
(判断字符串是否为非空),例如 if [ -n $(git remote | grep github) ]
。 -e
判断是否是文件(包括文件夹和特殊文件),-h
判断是否为 symlink,file1 -nt file2
(newer than),file1 -ot file2
(older than),-r, -w, -x
是否是文件且具有读写执行权限。
if [ string1 = string2 ]
判断字符串是否相等,string1 != string2
判断是否不相等。
-z
检查后面的内容是否为空.
-n
检查是否为非空
-v
检查变量是否有定义(定义为空字符也算)
双方括号不属于 POSIX 标准而是 bash 和 zsh 等特有的。语法更为现代
if [[ $a == $b ]]; then
判断相等,另有 !=
, <
, >
等。注意 <=
注意比较的不是数值大小而是字符串排序大小。
if [[ "字符串" =~ 正则表达式 ]]
可以判断字符串是否匹配正则表达式。其中正则表达式的格式和 grep -E
中的是一样的。例如 if [[ "$var" =~ ^-?[0-9]+$ ]]
判断变量是否表示整数。
# 判断文件是否为空
if [ -s 文件名 ]; then
# The file is not-empty.
else
# The file is empty.
fi
# 比较数字大小
if (( a > b )); then
...
fi
#!/bin/bash
for ((i = 1; i < 5; ++i))
# for i in {1,2,3,4} # 等效
# for i in 1 2 3 4 # 等效
do
printf "\nfile${i}.txt\n"
done
如果在 printf
语句后面加上 && break
,当前者失败时就会跳出循环。
另外 continue
也可以跳出循环
在当前目录中所有子目录循环
for d in */ ; do
d=${d%/} # 删除目录名最后的斜杠
echo "$d" # 打印所有子目录名
done
文件循环
for file in *; do
if [ -f "$file" ]; then
echo "$file"
fi
done
#!/bin/bash
arr=(1 3 hello 13)
for ((i=0;i<4;++i))
do
printf "arr[${i}] = ${arr[i]}\n"
done
例子
#!/bin/bash
# 确保文件最后有两个空格
# use `find . -type f -name "*.matt" -exec ./convert_matt.sh {} \;`
# to convert subfolder
file=${1}
printf "${file}... "
c2=$(tail -c 2 ${file})
if [ "${c2}" == " " ]
then
printf "already in new format\n"
else
printf " " >> ${file}
printf "done\n"
fi
$0
当前 shell script 的文件名,例如调用脚本的命令是 some/../path/test.sh
,那就返回这串字符。如果用 source some/path/test.sh
或者直接在命令行打 $0
,那么就返回 bash
。
$@
返回所有 shell arguments
$?
上一个命令的 exit status,0
代表成功,否则失败
readlink -f "$0"
获取脚本绝对路径(包括脚本文件名)(不可以直接在命令行使用,或者 source 脚本.sh
时使用)
dirname $(readlink -f "$0")
获取脚本所在绝对目录(不包括脚本文件名)
函数名() {
...
}
$1, $2
或者 ${1}, ${2}
,例如
greeting() {
echo "Hello $1"
}
greeting "Joe"
$0
是调用脚本的命令(也就是 argv[0]
)。$#
可以查看 args 的总个数
一个用于确保执行成功的函数:
check_failure() {
if [ $1 -ne 0 ]; then
echo "Error! Exiting..."
exit 1
fi
}
cmd1 arg1 && cmd2 arg2
check_failure $?
lsb_release -rs
可以获取 ubuntu 的系统版本号(例如 18.04
)
getconf _NPROCESSORS_ONLN
可以查看系统有多少逻辑 cpu