解析 shell 脚本的参数,记录。
不是简单的传参数进去的那种,那个用$1接就行了= =
-f config.json这种

#抄作业 👇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# otest
for i in "$@"; do
case $i in
-b=*|--batch_size=*)
sh_batch_size="${i#*=}"
shift
;;
-s=*|--data_file=*)
sh_data_file="${i#*=}"
shift
;;
-e=*|--epoch=*)
sh_epoch="${i#*=}"
shift
;;
-d=*|--data_dir=*)
sh_data_dir="${i#*=}"
shift
;;
-r=*|--res_model_dir=*)
sh_res_model_dir="${i#*=}"
shift
;;
-p=*|--pretrained_model_dir=*)
sh_pretrained_model_dir="${i#*=}"
shift
;;
*)
# unknown option
;;
esac
done

echo "batch_size = ${sh_batch_size}"
echo "data_dir = ${sh_data_dir}"
echo "data_file = ${sh_data_file}"
echo "epoch = ${sh_epoch}"
echo "output_dir = ${sh_res_model_dir}"
echo "pretrained_model_dir = ${sh_pretrained_model_dir}"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
➜  ~  otest                                              [2021/12/11 21:43:20]
batch_size =
data_dir =
data_file =
epoch =
output_dir =
pretrained_model_dir =
➜ ~ otest -b=64 -s=data_file.txt -e=80 -d=/data -r=/output -p=pre-model/p.tar
batch_size = 64
data_dir = /data
data_file = data_file.txt
epoch = 80
output_dir = /output
pretrained_model_dir = pre-model/p.tar

#为什么

  • 虽然各自语言都有 flag 包的实现,但是 shell 脚本作为入口可定制性最高,可以做些预处理和后处理。
  • 有些平台是固定参数的,需要包一层做参数转义,shell 无疑是最方便的。
  • 学一下总是没坏处的。

#$@

1
2
3
4
5
6
7
# otest
echo '$0:' "$0"
echo '$1:' "$1"
echo '$#:' "$#"
echo '$*:' "$*"
echo '$@:' "$@"
echo '$$:' "$$"
1
2
3
4
5
6
7
8
9
➜  ~  otest 1 2                                          [2021/12/11 21:24:05]
$0: /Users/onns/Onns/code/bash/otest
$1: 1
$#: 2
$*: 1 2
$@: 1 2
$$: 83125
➜ ~ echo $? [2021/12/11 21:24:29]
0

shell 里的一些特殊变量:

  • $0文件名(看起来是绝对路径)
  • $#参数个数,不包括本身
  • $$进程 id
  • $?获取上一个程序的返回值,或者上一个函数的 return 值

$*$@不被双引号包围时,没有区别。
被包裹时:

1
2
3
4
5
6
7
8
# otest
for i in "$@"; do
echo $i
done

for i in "$*"; do
echo $i
done
1
2
3
4
➜  ~  otest 1 2                                          [2021/12/11 21:24:31]
1
2
1 2

所以$@可以拿到所有参数。

#case

  • ;;相当于 break
  • string)相当于 case 的某一个条件,说是string其实不标准,应该叫pattern,这里用了*代表全匹配,用了|代表或,其实就是参数的简称和全称,全称可读性高,但是简称方便。
  • shift n可以将n个参数丢弃,n 省略则为1
1
2
3
4
5
6
# otest
echo '$#:' "$#"
echo '$*:' "$*"
shift 3
echo '$#:' "$#"
echo '$*:' "$*"
1
2
3
4
5
➜  ~  otest 1 2 3 4 5                                    [2021/12/11 21:43:28]
$#: 5
$*: 1 2 3 4 5
$#: 2
$*: 4 5

shift作用就是在解析完参数之后丢弃。

#${i#*=}

作用:只取${i}变量=右边的东西。

详细可以参考:https://onns.xyz/blog/2021/05/02/the-linux-command-line-note-27/

1
2
3
4
5
6
7
8
9
10
11
12
13
# otest
i="abacbbbdag"
echo "i: ${i}"
echo "i: ${i#*a}" # 从左往右 删除到符合`*a`匹配的最短串
echo "i: ${i##*a}" # 从左往右 删除到符合`*a`匹配的最长串
echo "i: ${i#*b}"
echo "i: ${i##*b}"
echo "-----------"
echo "i: ${i}"
echo "i: ${i%a*}" # 从右往左 删除到符合`a*`匹配的最短串
echo "i: ${i%%a*}" # 从右往左 删除到符合`a*`匹配的最长串
echo "i: ${i%b*}"
echo "i: ${i%%b*}"
1
2
3
4
5
6
7
8
9
10
11
12
➜  ~  otest 1 2 3 4 5                                    [2021/12/11 22:09:04]
i: abacbbbdag
i: bacbbbdag
i: g
i: acbbbdag
i: dag
-----------
i: abacbbbdag
i: abacbbbd
i:
i: abacbb
i: a

#结尾

因为平台是通过=传参的,所以写了这种方式,另一种方式同理的,或者看下参考链接里第二个的实现。

#参考文档

22:14:07 done