Linux-Shell 编程技巧学习 - 2

Introduction

Shell 脚本的执行逻辑:

准确来讲,shell 会先将脚本写入内存进行执行;这样对脚本进行修改时,便不会生效;

那么在流程代码编写中,我们可以尽量将可能需要修改的代码其中放在另一个外置的脚本中;只需要额外添加一个轮询脚本便可。

在轮询脚本中导入前面外置的脚本,便可实现每次导入脚本时,都会重新将该脚本写入

这样便可在不用重投轮询脚本的前提下对修改后的主脚本生效

Getting Started

续上 Linux-Shell 编程技巧学习-1

1. Shell 编程的外置参数设置

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
## 1. 常规判断输出的参数个数是否满足条件
## 缺点:参数不能乱序,可读性较差
options1(){
if [[ $# != 3 ]]; then
echo -e "USAGE: $ sh $0 str1 str2 ..."
exit 1;
fi
}

## 2. 设置参数时,指定参数的变量名
## 缺点:灵敏性低,无法检测参数传入的准确
options2(){
while getopts ":a:b:c:" opt
do
case $opt in
a)
str1=$OPTARG
echo -e "参数a: $str1"
;;
b)
str2=$OPTARG
echo -e "参数b: $str2"
;;
c)
str3=$OPTARG
echo -e "参数c: $str3"
;;
:)
echo -e "没有输入任何项: -$OPTARG"
exit 1
;;
?)
echo -e "错误的传参方式!!!\n\nUSAGE: $ sh $0 -a str1 -b str2 -c str3"
exit 1
;;
esac
done
}

## 3. 结合长短参数设置,灵活处理
## 缺点:一个选项只能读入一个参数,多余
usage(){
cat <<EOF
Usage:
$0 -i readid -s ATGC... [OPTION] ...

Known values for OPTION are:

-i/--readname read name/FusionName
-s/--sequence query sequence
-h/--help print this help and exit
-b/--blat the blat path (default: $blatPath_default)
-d/--database the database path (default: $database_default)
-a/--anno the transvar path (default: $transvar_default)
-c/--chr the query chr (default: all)
--show print this result (default: false)

author = Jwei
date = 2023-03-16
EOF
exit 1
}

ARGS=$(getopt -o hi:s:d:b:a:c: -l readname:,sequence:,database:,blat:,anno:,chr:,show,\help -n $0 -- "$@")
eval set -- "$ARGS"

while true
do
[ -z "$1" ] && exit 1;
case "$1" in
-i|--readname)
readName=$2
[ -z "$readName" ] && usage
shift 2 ;;
-s|--sequence)
sequence=$2
[ -z "$sequence" ] && usage
shift 2 ;;
-d|--database)
database_n=${2:-$database_default}
shift 2 ;;
-b|--blat)
blatPath_n=${2:-$blatPath_default}
shift 2 ;;
-a|--anno)
transvar_n=${2:-$transvar_default}
shift 2 ;;
-c|--chr)
chrq=":$2"
shift 2 ;;
--show)
show="True"
shift ;;
-h|--help)
usage
shift ;;
--)
shift
break
;;
*)
usage
shift
;;
esac
done

## 4. 对(3.)进行简单改写,可支持一个选项读入多个参数
ARGS0=$(echo $@ | awk -F' ' '{for(i=1;i<=NF;i++){if($i~/^-/){opt=$i;}else{printf "%s ",""opt" '\''"$i"'\''"}}}' | awk '{sub(/[\t ]$/,"");print}')
eval set -- "$ARGS0 --"
while true
do
[ -z "$1" ] && exit 1;
case "$1" in
-b|--bam)
bam+=",$2"
[ -z "$bam" ] && usage
shift 2 ;;
-p|--pos)
pos+=",$2"
[ -z "$pos" ] && usage
shift 2 ;;
-h|--help)
usage
shift ;;
--)
shift
break
;;
*)
usage
shift
;;
esac

done

2. while read

需要注意的是,通过管道符传递的参数只在其子进程生效,主进程将无法读取该变量;

但可以通过重定向让 while read 在主进程中运行,这样其中产生的变量就可在主进程中有效调用

1
2
3
4
5
6
7
8
9
## 子进程,主进程无法读取该循环中产生的变量
$ cat sample.path.list | while read sample path...;do
something ...;
done

## 循环ti
$ while read sample path ...;do
something ...;
done <<< "$(cat sample.path.list)"

References

忘了记录,如有雷同,可联系引用/删稿。手动狗头 ~ ~ ~