References
Shebang
#!/bin/bash
# 在 shebang 行中使用 env 命令
#!/usr/bin/env python
Variables
# 定义变量
var="a string" #等号两边不能有空格
#调用变量
echo $var
echo ${var}
# `""` suppress expansions except parameter expansion, arithmetic expansion, and command substitution
echo "$var" # 双引号会渲染变量,输出`a string`
# `''` suppress all expansions
echo '$var' # 单引号不会渲染变量,输出`$var`
# Arithmetic Expansion
echo $((1+1)) # 输出`2`
echo $((1.0/2)) # 输出`0.5`
# Command Substitution
# 执行命令并将输出替换原来内容
`cat some.txt`
$( cat some.txt )
# Process Substitution
# 执行命令并将输出写到一个临时文件中,并用临时文件名替换原来内容
# 在我们希望返回值通过文件而不是STDIN传递时很有用
diff <(ls foo) <(ls bar) #显示文件夹`foo`和`bar`中文件的区别
# Globbing 通配符
# `?`匹配一个字符,`*`匹配任意个字符
rm foo*
# Brace Expansion
# 花括号展开
echo Number_{1..5}
echo Front-{A,B,C}-Back
Positional Paramaters
$0
:路径- dirname $0:路径名
- basename $0:文件名
$1
~$9
:输入参数$@
: 所有参数,$*
:区别是会展开双引号中的参数$#
: 参数个数$?
:上一次退出状态,0为正常,其他为错误$$
: 当前脚本的进程识别码
Logit
Expression | Logit |
---|---|
[[ exp1 && exp2 ]] | and |
[[ exp1 || exp2 ]] | or |
[[ ! exp1 ]] | not |
# do command2 if command1 is sucessful
command1 && command2
# do command2 if command1 is unsucessful
command1 || command2
Function
function func {
commands
return
}
# or
func () {
commands
return
}
# local variable
function func {
local var
var=2
return
}
# function arguments
func () {
echo "Parameter #1 is $1" # arguments are refered by position
}
func "$arg1" "$arg2" # call function with arguments
Branching and Looping
If
x=5
if [[ $x -eq 5 ]]; then
echo "x equals 5."
elif [[ $x -eq 4 ]]; then
echo "x equals 4."
else
echo "x does not equal 5 or 4."
fi
Case
read -p
case $REPLY in
0) echo "zero"
;;
1) echo "one"
;;
2) echo "two"
;;
*) echo "other"
;;
esac
While
count=1
while [[ $count -le 5 ]]; do
echo $count
count=$((count + 1))
done
while true; do
echo 1
sleep 1
done
For
for (( i=0; i<5; i=i+1 )); do
echo $i
done
for i in {1..100}; do
echo $i
done
# iterate arguments from the 3rd
for i in "${@:3}"; do
echo $i
done
Test
尽量使用双方括号 [[ ]]
而不是单方括号 [ ]
,这样会降低犯错的几率,尽管这样并不能兼容 sh
File test
Expression | True |
---|---|
[ -e file ] | file exists |
[ -d file ] | file exists and is a directory |
[ -f file ] | file exists and is a regular file |
[ file1 -ef file2 ] | the two filenames refer to the same file by hard linking |
String test
Expression | True |
---|---|
[ string ] | not null |
[ -n string ] | The length is greater than zero |
[ -z string ] | The length is zero |
[ string1 = string2 ] | equal |
[ string1 != string2 ] | not equal |
[ string1 > string2 ] | string1 sorts after string2 |
[[ string =~ regex ]] | matched by the regular expression |
[[ string == *.txt ]] | matched by the expansion |
Integer test
if ((INT < 0)); then
echo "here"
elif (( ((INT % 2)) == 0)); then
echo "here"
elif (( ((INT % 2)) == 0 && ((INT % 3)) == 0 )); then
echo "here"
else
echo "here"
fi
Command test
if ls /root; then
echo success
else
echo fail
fi
if ! grep $host $machines_file; then
echo not found
fi
ls /nonexistent
if [ $? -ne 0 ]; then
# command returned non-zero
else
# command returned 0
fi
常用用法
多行输入
# here document
command <<- _EOF_
text
_EOF_
读取输入
read a
echo "input is a=${a}"
导入其他变量
config.sh
定义常量
const1=1
const2='a'
导入变量
source config.sh
脚本选项
# Option parsing
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-q|--quiet)
QUIET=true
;;
-n|--filename)
FILENAME="$2"
shift
;;
-h|--help)
usage
exit 0
;;
*)
(>&2 printf "Unknown parameter: %s\n" "$1")
usage
exit 1
;;
esac
shift
done
if [ ! "$QUIET" ]; then
echo "verbose"
fi
getops
#!/bin/bash
# Echo usage if something isn't right.
usage() {
echo "Usage: $0 [-p <80|443>] [-h <string>] [-f] <arg>" 1>&2; exit 1;
}
while getopts ":p:h:fg" o; do
case "${o}" in
p)
arg_port=${OPTARG}
[[ $arg_port != "80" && $arg_port != "443" ]] && usage
;;
h)
arg_host=${OPTARG}
;;
f)
flag_f=1
;;
g)
flag_g=1
;;
:)
echo "ERROR: Option -$OPTARG requires an argument"
usage
;;
\?)
echo "ERROR: Invalid option -$OPTARG"
usage
;;
esac
done
shift $((OPTIND-1))
# Check required switches exist
if [ -z "${arg_port}" ] || [ -z "${arg_host}" ]; then
usage
fi
if (( flag_f > 0 )); then
echo "p = ${arg_port}"
echo "h = ${arg_host}"
fi
if (( flag_g > 0 )); then
for arg in "$@"; do
args+=("$arg")
echo $arg
done
fi
-
the first
:
denote ifgetopts
should throw an error if parameters are missing -
p:
expects-p
with an attribute -
f
with no colon expects-f
with no attribute -
shift $((OPTIND-1))
removes all the options that have been parsed bygetopts
-
for arg in "$@"
iterate the rest arguments -
usage example:
myscript.sh -p 443 -h myhost.com -f some_arg
调用 Python
curl -s "${URL}" | python -c 'import sys, json; print(json.load(sys.stdin)["images"][0]["url"])' > "$CACHE_DIR"/$(date +%Y-%m-%d).jpg