├── .gitignore
├── .travis.yml
├── README.org
├── cheatsheet-shell-A4.pdf
├── code
├── assert-user-root.sh
├── curl-test.sh
├── exec
│ ├── README.md
│ ├── sub.sh
│ ├── test.sh
│ ├── test2.sh
│ └── test3.sh
├── file
│ ├── remove-old-files
│ │ └── readme.md
│ ├── tenth-line
│ │ ├── file.txt
│ │ ├── readme.md
│ │ └── test.sh
│ ├── transpose-file
│ │ ├── file.txt
│ │ ├── readme.md
│ │ └── test.sh
│ └── word-frequency
│ │ ├── readme.md
│ │ ├── test.sh
│ │ └── words.txt
├── log-with-timestamp.sh
├── long-option-parameter.sh
├── misc
│ └── quiz_sample.png
├── network
│ └── get_ip_from_eth0
│ │ ├── readme.md
│ │ └── test.sh
├── restore-debug-output.sh
├── shell-retry.sh
├── string-contains.sh
├── string-in-list.sh
├── string
│ ├── shell-escape
│ │ └── readme.md
│ └── valid-phone-numbers
│ │ ├── file.txt
│ │ ├── readme.md
│ │ └── test.sh
└── trap-exit.sh
└── zsh_disable
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.tex
3 | README.pdf
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: bash
2 | install:
3 | # Install a custom version of shellcheck instead of Travis CI's default
4 | - scversion="stable" # or "v0.4.7", or "latest"
5 | - wget "https://storage.googleapis.com/shellcheck/shellcheck-$scversion.linux.x86_64.tar.xz"
6 | - tar --xz -xvf "shellcheck-$scversion.linux.x86_64.tar.xz"
7 | - shellcheck() { "shellcheck-$scversion/shellcheck" "$@"; }
8 | - shellcheck --version
9 |
10 | script:
11 | - find . -name *.sh | xargs shellcheck
12 |
--------------------------------------------------------------------------------
/README.org:
--------------------------------------------------------------------------------
1 | * Shell CheatSheet :Languages:
2 | :PROPERTIES:
3 | :type: language
4 | :export_file_name: cheatsheet-shell-A4.pdf
5 | :END:
6 |
7 | #+BEGIN_HTML
8 |
9 |
14 |
15 |
16 |
17 | #+END_HTML
18 |
19 | - PDF Link: [[https://github.com/dennyzhang/cheatsheet-shell-A4/blob/master/cheatsheet-shell-A4.pdf][cheatsheet-shell-A4.pdf]], Category: [[https://cheatsheet.dennyzhang.com/category/languages][languages]]
20 | - Blog URL: https://cheatsheet.dennyzhang.com/cheatsheet-shell-A4
21 | - Related posts: [[https://cheatsheet.dennyzhang.com/cheatsheet-vim-A4][Vim CheatSheet]], [[https://github.com/topics/denny-cheatsheets][#denny-cheatsheets]]
22 |
23 | File me [[https://github.com/dennyzhang/cheatsheet.dennyzhang.com/issues][Issues]] or star [[https://github.com/dennyzhang/cheatsheet.dennyzhang.com][this repo]].
24 | ** Basic
25 | | Name | Comment |
26 | |----------------------------------------+-----------------------------------------------------------------------|
27 | | Redirect stdout/stderr | =ls /tmp >/dev/null 2>&1= |
28 | | Deal with filename | =basename $f=, =dirname $f= |
29 | | Use timeout: avoid command hang | timeout 10 sh -c 'ls -lt' |
30 | | Restart shell without killing terminal | =exec -l $SHELL= |
31 | | Run sub-shell | =echo $BASH_SUBSHELL; ( echo "Running in subshell: $BASH_SUBSHELL" )= |
32 | | Set pipefail | =set -ueoxv pipefail=, =set +ueoxv pipefail= |
33 | | Shell match regexp | =echo $str, then grep "$regexp"= |
34 | | Shell match regexp | =expr match "$date" "^[0-9]\{8\}" >/dev/null && echo yes= |
35 | | Run static code check | [[https://www.dennyzhang.com/shellcheck][Link: shellcheck]] |
36 | | Show date in utc | =date -u= |
37 | | Check file type of a given type | =file /etc/hosts= |
38 | | Check command type of a command | =type echo= |
39 | ** Shell script
40 | | Name | Comment |
41 | |----------------------------------------+---------------------------------------------|
42 | | Trap exit signal | [[https://github.com/dennyzhang/cheatsheet-shell-A4/blob/master/code/trap-exit.sh][code/trap-exit.sh]] |
43 | | Shell retry | [[https://github.com/dennyzhang/cheatsheet-shell-A4/blob/master/code/shell-retry.sh][code/shell-retry.sh]] |
44 | | Check if a string contains a substring | [[https://github.com/dennyzhang/cheatsheet-shell-A4/blob/master/code/string-contains.sh][code/string-contains.sh]] |
45 | | Check if a string in a list | [[https://github.com/dennyzhang/cheatsheet-shell-A4/blob/master/code/string-in-list.sh][code/string-in-list.sh]], [[https://stackoverflow.com/questions/8063228/how-do-i-check-if-a-variable-exists-in-a-list-in-bash][Link: stackoverflow]] |
46 | | Log with timestamp | [[https://github.com/dennyzhang/cheatsheet-shell-A4/blob/master/code/log-with-timestamp.sh][code/log-with-timestamp.sh]] |
47 | | Quit if current user is not root | [[https://github.com/dennyzhang/cheatsheet-shell-A4/blob/master/code/assert-user-root.sh][code/assert-user-root.sh]] |
48 | | Set -x on fly | [[https://github.com/dennyzhang/cheatsheet-shell-A4/blob/master/code/restore-debug-output.sh][code/restore-debug-output.sh]] |
49 | | Shell run curl check | [[https://github.com/dennyzhang/cheatsheet-shell-A4/blob/master/code/curl-test.sh][code/curl-test.sh]] |
50 | ** Environment variables
51 | | Name | Comment |
52 | |------------------------------------------------+------------------------------------|
53 | | List all environment variables | =export= |
54 | | Define a new env variable | export NAME1="value1" |
55 | | Define a variable with default value of others | export MYVAR="${MYVAR:-$OTHERVAR}" |
56 | ** iterm
57 | | Name | Comment |
58 | |---------------+---------|
59 | | Delete a word | Ctrl+w |
60 | ** zsh
61 | | Name | Comment |
62 | |-------------------------------+-----------------------------------------------------|
63 | | Disable all zsh's autocorrect | In ~/.zshrc, =unsetopt correct_all= |
64 | | Disable a given autocorrect | In ~/.zshrc, alias ssh='nocorrect ssh'. [[https://github.com/dennyzhang/cheatsheet-shell-A4/blob/master/code/restore-debug-output.sh][zsh_disable]] |
65 | ** GNU tools
66 | *** Echo string
67 | | Name | Comment |
68 | |----------------------+---------------------------------------------------------|
69 | | Echo red text | echo -e "hello,\e[0;31m there \e[0;31m" |
70 | | Echo multiple lines | echo -e "hello,\ndenny" |
71 | | Echo bold text | echo -e hello, "\033[1mThis is bold text.\033[0m" |
72 | | Echo underlined text | echo -e hello, "\033[4mThis is underlined text.\033[0m" |
73 | ** Shell Basic
74 | *** cd
75 | | Name | Comment |
76 | |--------------------------+---------------------------------------------------------|
77 | | Go to given folder | =cd /var/log/= |
78 | | Go to folder in subshell | =(cd /var/log/ && ls)= After this, PWD won't be changed |
79 | | Go to home | =cd= |
80 | | Go to parent folder | =cd ..= |
81 | | Go to previous folder | =cd -= |
82 | #+BEGIN_HTML
83 |
84 | #+END_HTML
85 | *** Numeric
86 | | Name | Comment |
87 | |------+------------------------------------------------|
88 | | * | =expr 5 \* 4= |
89 | | + | =let z=x+y, z=$x+$y= |
90 | | == | =int1 -eq int2=, =[ $? -eq 0 ] && echo "good"= |
91 | | >= | =int1 -ge =int2= |
92 | | > | =int1 -gt =int2= |
93 | | <= | =int1 -le =int2= |
94 | | < | =int1 -lt =int2= |
95 | | != | =int1 -ne =int2= |
96 | *** xargs
97 | #+BEGIN_SRC sh
98 | # Run grep for files filtered by find
99 | find /var/log -name "*.log" | xargs grep -i error
100 |
101 | # Loop with pipes
102 | cat /etc/passwd | awk -F':' '{print $1}' | xargs -I{} sudo -l -U {} | grep -v "not allowed to"
103 | #+END_SRC
104 | ** Scripts
105 | - Compare command output
106 | #+BEGIN_SRC sh
107 | [ 0 -eq $(find ./data -name "*.txt" -type f -print | wc -l) ]
108 | #+END_SRC
109 |
110 | - get ip from eth0
111 | #+BEGIN_SRC sh
112 | /sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'
113 | #+END_SRC
114 | ** More Resources
115 | License: Code is licensed under [[https://www.dennyzhang.com/wp-content/mit_license.txt][MIT License]].
116 | #+BEGIN_HTML
117 |
118 |
119 |
120 |
121 |
122 |
123 | #+END_HTML
124 | * org-mode configuration :noexport:
125 | #+STARTUP: overview customtime noalign logdone showall
126 | #+DESCRIPTION:
127 | #+KEYWORDS:
128 | #+LATEX_HEADER: \usepackage[margin=0.6in]{geometry}
129 | #+LaTeX_CLASS_OPTIONS: [8pt]
130 | #+LATEX_HEADER: \usepackage[english]{babel}
131 | #+LATEX_HEADER: \usepackage{lastpage}
132 | #+LATEX_HEADER: \usepackage{fancyhdr}
133 | #+LATEX_HEADER: \pagestyle{fancy}
134 | #+LATEX_HEADER: \fancyhf{}
135 | #+LATEX_HEADER: \rhead{Updated: \today}
136 | #+LATEX_HEADER: \rfoot{\thepage\ of \pageref{LastPage}}
137 | #+LATEX_HEADER: \lfoot{\href{https://github.com/dennyzhang/cheatsheet-shell-A4}{GitHub: https://github.com/dennyzhang/cheatsheet-shell-A4}}
138 | #+LATEX_HEADER: \lhead{\href{https://cheatsheet.dennyzhang.com/cheatsheet-shell-A4}{Blog URL: https://cheatsheet.dennyzhang.com/cheatsheet-shell-A4}}
139 | #+AUTHOR: Denny Zhang
140 | #+EMAIL: denny@dennyzhang.com
141 | #+TAGS: noexport(n)
142 | #+PRIORITIES: A D C
143 | #+OPTIONS: H:3 num:t toc:nil \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t
144 | #+OPTIONS: TeX:t LaTeX:nil skip:nil d:nil todo:t pri:nil tags:not-in-toc
145 | #+EXPORT_EXCLUDE_TAGS: exclude noexport
146 | #+SEQ_TODO: TODO HALF ASSIGN | DONE BYPASS DELEGATE CANCELED DEFERRED
147 | #+LINK_UP:
148 | #+LINK_HOME:
149 | * # --8<-------------------------- separator ------------------------>8-- :noexport:
150 | * [#A] Difficulties in shell/bash :noexport:Coding:Personal:
151 | :PROPERTIES:
152 | :type: Linux_Language
153 | :END:
154 |
155 | [[https://www.dennyzhang.com/wp-content/uploads/2014/04//blog_bash.png]]
156 | | Item | Summary |
157 | |----------------------------------------------------------------+-------------------------------------------------------------|
158 | | ${cmds}/$(cmd) | 在当前shell中执行命令/在子shell中执行命令 |
159 | | ${x}y/$xy | 将变量x连上字符y/变量xy |
160 | | $*/$@ | 当某个输入变量含空格时, 两者是不同的 |
161 | |----------------------------------------------------------------+-------------------------------------------------------------|
162 | | type | 查看命令的类型(内置命令,别名,函数,可执行文件等) |
163 | | (sh /tmp/1.sh ; echo "error code $?") >/tmp/1.log | 追加sh运行后的$?于log文件 |
164 | | read -e variablename | 读取用户输入 |
165 | | eval __value="\$$env" | eval命令在处理命令行时,先执行所有的shell替换,然后执行命令行 |
166 | | /bin/sh -xe /tmp/hudson366585559507073478.sh | echo shell |
167 | | declare -a PRE_ROLLING_SCRIPT=`cat $output_file` | 申明变量 |
168 | ** 测试操作 -- test :noexport:
169 | - test命令会修改$?的值
170 |
171 | | Item | Summary |
172 | |---------------------------+-----------------------|
173 | | test -z str | 判断字符串str是否为空 |
174 | | str1 = str2 | str1是否与str2相同 |
175 | | -d | 是否一个目录 |
176 | | -e | 文件是否存在 |
177 | | [ "" == "$diff_content" ] | |
178 |
179 | [ 75 == `svn info ./manifests/localnet/setting.pp.sample | grep Revision | awk -F': ' '{print $2}'` ]
180 | *** 示例代码
181 | #+BEGIN_EXAMPLE
182 | myPath="/var/log/httpd/"
183 | myFile="/var /log/httpd/access.log"
184 |
185 | #这里的-x 参数判断$myPath是否存在并且是否具有可执行权限
186 | if [ ! -x "$myPath"]; then
187 | mkdir "$myPath"
188 | fi
189 |
190 | #这里的-d 参数判断$myPath是否存在
191 | if [ ! -d "$myPath"]; then
192 | mkdir "$myPath"
193 | fi
194 |
195 | #这里的-f参数判断$myFile是否存在
196 | if [ ! -f "$myFile" ]; then
197 | touch "$myFile"
198 | fi
199 |
200 | #其他参数还有-n,-n是判断一个变量是否是否有值
201 | if [ ! -n "$myVar" ]; then
202 | echo "$myVar is empty"
203 | exit 0
204 | fi
205 |
206 | #两个变量判断是否相等
207 | if [ "$var1" = "$var2" ]; then
208 | echo '$var1 eq $var2'
209 | else
210 | echo '$var1 not eq $var2'
211 | fi
212 | #+END_EXAMPLE
213 | *** shell中常用系统变量和条件判断
214 | http://blog.chinaunix.net/u/28814/showart_1422464.html\\
215 | #+begin_example
216 | shell中常用系统变量和条件判断
217 | 常用系统变量
218 | $0 当前程序的名称
219 | $n 当前程序的第n个参数,n=1,2,...9
220 | $* 当前程序的所有参数(不包括程序本身)
221 | $# 当前程序的参数个数(不包括程序本身)
222 | $$ 当前程序的PID
223 | $! 执行上一个子进程的PID
224 | $? 执行上一个指令的返回值
225 | 条件判断:expression为字符串操作
226 | -n str 字符串str是否不为空
227 | -z str 字符串str是否为空
228 | str1 =str2 str1是否与str2相同
229 | str1!=str2 str1是否与str2不同
230 | 条件判断:expression为整数操作
231 | expr1 -a expr2 如果 expr1 和 expr2 评估为真,则为真
232 | expr1 -o expr2 如果 expr1 或 expr2 评估为真,则为真
233 | 条件判断:expression为bool操作
234 | int1 -eq int2 如果int1等于int2,则为真
235 | int1 -ge int2 如果int1大于或等于int2,则为真
236 | int1 -gt int2 如果int1大于int2 ,则为真
237 | int1 -le int2 如果int1小于或等于int2 ,则为真
238 | int1 -lt int2 如果int1小于int2 ,则为真
239 | int1 -ne int2 如果int1不等于int2 ,则为真
240 | 条件判断:expression为文件操作
241 | -b 是否块文件 -p 文件是否为一个命名管道
242 | -c 是否字符文件 -r 文件是否可读
243 | -d 是否一个目录 -s 文件的长度是否不为零
244 | -e 文件是否存在 -S 是否为套接字文件
245 | -f 是否普通文件 -x 文件是否可执行,则为真
246 | -g 是否设置了文件的 SGID 位 -u 是否设置了文件的 SUID 位
247 | -G 文件是否存在且归该组所有 -w 文件是否可写,则为真
248 | -k 文件是否设置了的粘贴位 -t fd fd 是否是一个与终端相连的打开的文件描述符(fd 默认为 1)
249 | -O 文件是否存在且归该用户所有
250 | #+end_example
251 | ** 任务操作 -- Job :noexport:
252 | | 命令 | 含义 |
253 | |-------------+--------------------------------------------------------------|
254 | | bg | 启动被终止的后台作业 |
255 | | fg | 将后台作业调到前台 |
256 | | jobs | 列出所有正在运行的作业 |
257 | | kill | 向指定作业发送kill信号 |
258 | | ^Z(Ctrl-Z) | 终止(挂起)作业.屏幕上将出现提示符 |
259 | |-------------+--------------------------------------------------------------|
260 | | stop | 挂起一个后台作业 |
261 | | stty tostop | 当一个后台作业向终端发送输出时就挂起它 |
262 | | wait[n] | 等待一个指定的作业并返回它的退出状态,这里n是一个PID或作业号 |
263 |
264 | - jobs命令的参数
265 | | jobs命令的参数 | 含义 |
266 | |----------------+----------------------|
267 | | %n | 作业号n |
268 | | %string | 以string开头的作业名 |
269 | | %?string | 作业名包含string |
270 | | %% | 当前作业 |
271 | | %+ | 当前作业 |
272 | | %- | 当前作业前的一个作业 |
273 | | -r | 列出所有运行的作业 |
274 | | -s | 列出所有挂起的作业 |
275 | *** basic use
276 | #+begin_example
277 | - shell的作业控制: C-z, bg, fg
278 | sleep 1000 #起一个前端作业
279 | ^Z # 将前端作业转到后台
280 | jobs -l #查看作业列表
281 | bg #启动被终止的后台作业
282 | jobs -l #查看作业列表
283 | fg #将后台作业调到前台
284 |
285 | jobs -r:列出所有运行的作业
286 | jobs -s:列出所有暂停的作业
287 | bg %2:启动后台运行中的第二个作业
288 | #+end_example
289 | *** DONE 特殊变量:$!最后一个后台作业ID, $?上一条命令的退出值, $$当前shell的PID
290 | CLOSED: [2010-03-04 星期四 13:02]
291 | | 变量 | 含义 |
292 | | '$' | 当前shell的PID |
293 | | '-' | 当前的sh选项设置 |
294 | | '?' | 已执行的上一条命令的退出值 |
295 | | '!' | 最后一个进入后台的作业的PID |
296 | #+begin_src sh
297 | echo The pid of this shell is $$
298 | echo The options for this shell are $-
299 | grep ls /etc/passwd
300 | echo $?
301 | sleep 25 &
302 | echo $!
303 | #+end_src
304 | ** # --8<-------------------------- separator ------------------------>8--
305 | ** [question] Difference between the two shell commands: load_builtin_options VS $(load_builtin_options)
306 | ** [question] shell中all-servers不是合法变量名?
307 | *** console shot: :noexport:
308 | #+begin_example
309 | ,----------- /sshx:root@192.168.51.128:/home/zhangwei/hudsonecae/health_check/parse_conf.sh
310 | | all-servers="127.0.0.1"
311 | | ecae-servers="127.0.0.1"
312 | | embeded-ecae-services="ecae router webapp mongo memcache scm"
313 | | mysql-server="127.0.0.1" # TODO: what if multiple zookeeper servers
314 | `-----------
315 |
316 | ///c0f958ce1a270dc022d431edf2eff580#$./ecae-health-check.sh
317 | [2012-03-28 06:50:41] Parse configuration
318 | ./parse_conf.sh: line 14: all-servers=127.0.0.1: command not found
319 | ./parse_conf.sh: line 15: ecae-servers=127.0.0.1: command not found
320 | ./parse_conf.sh: line 16: embeded-ecae-services=ecae router webapp mongo memcache scm: command not found
321 | ./parse_conf.sh: line 17: mysql-server=127.0.0.1: command not found
322 | ./parse_conf.sh: line 19: zk-servers=127.0.0.1: command not found
323 | #+end_example
324 | ** [question] [ test=ab ]; echo $? 输出为什么为0
325 | ** [question] 如何在shell文件内部,将stdout重定向
326 | ** [question] 解释下面umask的行为
327 | #+begin_example
328 | ///c98c8cb7008ad33b849ed394ba96520d#$umask 0; mkdir /tmp/usr/local/ecae-health-check/report/t7
329 | ///c98c8cb7008ad33b849ed394ba96520d#$ls -lt /tmp/usr/local/ecae-health-check/report/
330 | total 36
331 | drwxrwxrwx 2 root root 4096 Jul 12 11:32 t7
332 | -rw-rw-rw- 1 root root 0 Jul 12 11:32 t5
333 | ----rw-rw- 1 root root 0 Jul 12 11:32 t4
334 | ---------- 1 root root 0 Jul 12 11:31 t3
335 | d--------- 2 root root 4096 Jul 12 11:31 t2
336 | d--------- 2 root root 4096 Jul 12 11:30 tt
337 | #+end_example
338 | ** [question] 下面ls命令输出之间的间隔符是什么
339 | #+begin_example
340 | ///60b852829888cc1252b5498d239e247c#$ls /tmp/elmar
341 | client data deps ebin if include priv rel src
342 | ///60b852829888cc1252b5498d239e247c#$ls /tmp/elmar > ./test
343 | ///60b852829888cc1252b5498d239e247c#$cat ./test
344 | client
345 | data
346 | deps
347 | ebin
348 | if
349 | include
350 | priv
351 | rel
352 | src
353 | ///60b852829888cc1252b5498d239e247c#$
354 | #+end_example
355 | ** [question] shell将如下代码定义成函数
356 | #+begin_src sh
357 | while [ -z "$all_servers" ] ; do
358 | echo -ne "Enter the ip list for all nodes in the system, separated by whitespace. Sample: 192.168.75.101 192.168.75.102\n> "
359 | read -e all_servers
360 | update_option_in_conf "$System_file" "all_servers" "$all_servers"
361 | done
362 | #+end_src
363 | ** [question] 解释下面shell执行的行为
364 | #+begin_example
365 | /sshx:root@192.168.51.102: #$ command='ps -ef | grep "run_erl.*elmar" | grep -v grep | awk -F'\'' '\'' '\''{print $2}'\'' | xargs lsof -p | wc -l'
366 | /sshx:root@192.168.51.102: #$ echo $command
367 | ps -ef | grep "run_erl.*elmar" | grep -v grep | awk -F' ' '{print $2}' | xargs lsof -p | wc -l
368 | /sshx:root@192.168.51.102: #$ ps -ef | grep "run_erl.*elmar" | grep -v grep | awk -F' ' '{print $2}' | xargs lsof -p | wc -l
369 | 12
370 | /sshx:root@192.168.51.102: #$ `command`
371 | /sshx:root@192.168.51.102: #$ $(command)
372 | /sshx:root@192.168.51.102: #$ echo $?
373 | 0
374 | /sshx:root@192.168.51.102: #$ echo $command
375 | ps -ef | grep "run_erl.*elmar" | grep -v grep | awk -F' ' '{print $2}' | xargs lsof -p | wc -l
376 | #+end_example
377 | ** # --8<-------------------------- separator ------------------------>8--
378 | ** Common misunderstood -- 常见疑点
379 | *** ${x}与$x的区别: ${x}y表示将变量x的值连接上字符y, $xy表示变量xy
380 | http://unix-school.blogspot.in/2011/07/difference-between-x-and-x.html\\
381 | *** $*与$@的区别
382 | *** Internal commands VS External commands
383 | http://unix-school.blogspot.in/2012/03/internal-vs-external-commands.html\\
384 | - Internal commands are something which is built into the shell.
385 | - When an external command has to be executed, a new process has to be spawned and the command gets executed.
386 | | Item | Comment |
387 | |----------------------------------------------------+----------|
388 | | get the list of Internal commands | help |
389 | | find out whether a command is internal or external | type cat |
390 | #+begin_src bash
391 | # For performance issue, better use internal commands, compared to external commands
392 |
393 | # Say to add 2 numbers say x & y:
394 |
395 | z=`expr $x+$y` # Not good
396 |
397 | let z=x+y #Good
398 | #+end_src
399 | ** 快捷键 -- Shortcut
400 | | Item | Summary |
401 | |----------------+------------------------------------------------------------------------------|
402 | | ^p, 上箭头 | 显示前一条命令 |
403 | | ^n, 下箭头 | 显示后一条命令 |
404 | | history [N] | 显示命令行历史或最近N条命令 |
405 | | 搜索命令行历史 | ^r启动搜索,输入任意字符串,显示以输入字符串开头的命令,^p显示前一条匹配结果 |
406 | ** 数组操作 -- list array
407 | | Item | Summary |
408 | |------------------------------------------------+---------------------------|
409 | | strs="ab cd"; lists=($strs) | shell字符串转成list |
410 | | strs="ab cd"; lists=($strs); echo ${lists[1]} | 取数组第二维 |
411 | | strs="ab cd"; lists=($strs); echo ${lists[*]} | 取出数组所有元素 |
412 | | for i in $(seq 5) | Generate range of numbers |
413 | | for a in "ab" "cd";do echo "12"$a;done; | 使用以string组成的list |
414 | | declare -a nums=(45 33 100 65) | 申明一个数组 |
415 | | a=(1 2 3 4); echo ${#a[@]} | 得到数组的大小 |
416 | *** DONE shell中使用数组: declare -a nums=(45 33 100 65) :IMPORTANT:
417 | CLOSED: [2010-03-04 星期四 13:39]
418 | #+begin_src sh
419 | declare -a friends
420 | friends=(Shery Peter Louise)
421 | echo ${friends<0>}
422 | echo ${friends<2>}
423 | echo "All the firneds are ${friends[*]}"
424 | echo "The number of elements in the array is ${#friends[*]}"
425 | unset friends
426 | #+end_src
427 | *** DONE [#A] 将"ab cd"作为一个数组来使用: ${lists[*]} :IMPORTANT:
428 | CLOSED: [2012-08-11 六 00:29]
429 | #+begin_example
430 | denny@denny-Vostro-1014:/proc$ strs="ab cd"
431 | denny@denny-Vostro-1014:/proc$ lists=($strs)
432 | denny@denny-Vostro-1014:/proc$ echo $lists
433 | ab
434 | denny@denny-Vostro-1014:/proc$ echo ${lists[0]}
435 | ab
436 | denny@denny-Vostro-1014:/proc$ echo ${lists[1]}
437 | cd
438 | denny@denny-Vostro-1014:/proc$ for a in ${lists[*]};do echo "12"$a;done;
439 | 12ab
440 | 12cd
441 | #+end_example
442 | *** DONE 给定一个list, 得到它的一个随机排列
443 | CLOSED: [2012-04-10 Tue 15:18]
444 | #+begin_src sh
445 | #!/bin/bash
446 | ## for a given list, return a new list with items re-arranged by random algorithm
447 | function generate_random_list()
448 | {
449 | local lists=${1?}
450 | local lists_ret array count
451 | lists_ret=""
452 | while [ ! -z "$lists" ]
453 | do
454 | array=($lists)
455 | count=${#array[*]} # item counts of the list
456 | index=$((RANDOM % $count))
457 | item=${array[$index]}
458 | lists=`echo $lists | sed 's/'$item'//g'` # remove the chosen item
459 | lists=${lists%% } # remove tailing whitespace
460 | lists_ret=$lists_ret" "$item
461 | #echo "count:"$count"index:"$index" item:"$item" lists:"$lists" lists_ret:"$lists_ret
462 | done
463 | echo $lists_ret
464 | }
465 | org_list="ab cd ef hb ed af"
466 | new_list=$(generate_random_list "$org_list")
467 | echo -e "org_list:"$org_list"\nnew_list:"$new_list
468 | #+end_src
469 | ** 目录相关操作 -- Directory
470 | | Item | Summary |
471 | |--------------------+------------------------------------------------------------------|
472 | | cd - | 回退当上一次的目录位置 |
473 | | (cd ./deps; ls af) | 进入目录后, 运行shell某个命令, 如果失败, 那么不修改当前的目录 |
474 | ** 文件操作 -- File
475 | | Item | Summary |
476 | |--------------------------------------------------------+----------------------------------|
477 | | sudo bash -c "echo hello >>/tmp/hosts" | 向权限不够的文件尾部追加一些内容 |
478 | | echo "test" | tee -a /test.log | 向权限不够的文件尾部追加一些内容 |
479 | | (cat /etc/hosts; echo "append") | sudo tee ./test.log | 向权限不够的文件尾部追加一些内容 |
480 | *** DONE globbing文件名替换:ls[!f-z]??? :IMPORTANT:
481 | CLOSED: [2010-03-04 星期四 11:44]
482 | globbing就是将元字符展开为文件名的过程.
483 |
484 | ls *.bak
485 | ls a?c?
486 | ls[!f-z]???
487 | ls f{oo,aa,umble}
488 | ** 字符串操作 -- string
489 | | 表达式 | 功能 |
490 | |---------------+------------------------------------------------------------|
491 | | ${变量%模式} | 将变量值的尾部与模式进行最小匹配,并将匹配的部分删除 |
492 | | ${变量%%模式} | 将变量值的尾部与模式进行最大匹配,并将匹配的部分删除 |
493 | | ${变量#模式} | 将变量值的头部与模式进行最小匹配,并将匹配的部分删除 |
494 | | ${变量##模式} | 将变量值的头部与模式进行最大匹配,并将匹配的部分删除 |
495 | | ${#变量} | 替换为变量中的字符个数.如果是*或@,长度则是位置参量的个数 |
496 | *** string compare
497 | #+BEGIN_EXAMPLE
498 | http://www.linux286.com/index.php/action_viewthread_tid_15502.html\\
499 | shell中常用系统变量和条件判断
500 | #+end_example
501 | *** 示例代码
502 | #+begin_src sh
503 | pathname="/usr/bin/local/bin"
504 | echo ${pathname%/bin*} # /usr/bin/local
505 | echo ${pathname%%/bin*} # /usr/
506 |
507 | pathname=/home/liliput/jake/.bashrc
508 | echo ${pathname#/home} # /liliput/jake/.bashrc
509 |
510 | pathname=/home/liliput/jake/.bashrc
511 | echo ${pathname##*/} # .bashrc
512 |
513 | name="Ebenezer Scrooge"
514 | echo ${#name} # 16
515 | ;; -------------------------- separator --------------------------
516 | # An IP range is like "10.32.182.181-184" or just a single IP address
517 | #
518 | function __util_parse_ip_range()
519 | {
520 | local range=${1?}
521 | local start_ip network start end
522 |
523 | if [[ $range == *-* ]]; then
524 | start_ip=${range%-*}
525 | end=${range##*-}
526 | util_check_ip start_ip && util_check_num end || {
527 | log_error "Invalid IP range '$range'"
528 | return 1
529 | }
530 |
531 | network=${start_ip%.*}
532 | start=${start_ip##*.}
533 | util_check_num start || {
534 | log_error "Invalid IP range '$range'"
535 | return 1
536 | }
537 |
538 | ((start <= end)) || {
539 | log_error "Invalid IP range '$range': end number '$end' is less" \
540 | "than start number '$start'"
541 | return 1
542 | }
543 |
544 | local x
545 | for ((x = start; x <= end; x++)); do
546 | echo -n "$network.$x "
547 | done
548 | else
549 | util_check_ip range || {
550 | log_error "Invalid IP range '$range' - neither a range nor an" \
551 | "single address"
552 | return 1
553 | }
554 | echo -n "$range "
555 | fi
556 |
557 | return 0
558 | }
559 | #+end_src
560 | *** TODO 从下面CONARY_NEW_VERSION变量中提取出1.2.3.32049
561 | CONARY_NEW_VERSION=/maui.lss.emc.com@emc:atmos-1.2-auto/1.2.3.32049-1-1
562 | *** DONE bash strip whitespace: ${var##*( )}
563 | CLOSED: [2016-04-15 Fri 07:47]
564 | http://www.cyberciti.biz/faq/bash-remove-whitespace-from-string/
565 | str2=$(echo "${str}" |sed -e 's/^[ \t]*//g')
566 | str2=$(echo "${str}" |sed -e 's/[ \t]*$//g')
567 |
568 | output=" This is a test"
569 | output="${output##*( )}"
570 | echo "=${output}="
571 | ** 随机 -- random
572 | | Item | Summary |
573 | |-----------------------+------------------------|
574 | | echo $((RANDOM % 10)) | 产生指定区间内的随机数 |
575 | ** shell的位置参量 -- 命令行参数
576 | | 位置参量 | 指代对象 |
577 | |----------+-----------------------------------------------|
578 | | $0 | 脚本名 |
579 | | $# | 位置参量的个数 |
580 | | $* | 所有的位置参量 |
581 | | $@ | 未加双引号时,与$*含义相同 |
582 | | "$*" | 扩展为单个变量(例如: "$1 $2 $3" |
583 | | "$@" | 扩展为多个单独的变量(例如:"$1", "$2", "$3") |
584 | | $1...$9 | 最多可引用9个位置参量 |
585 |
586 | - 带参数的set命令将重置位置参量.
587 | 位置参量一旦被重置,原来的参量列表就会丢失
588 | - 要想清除所有的位置参量,可使用set --
589 | - 比较$*与$@的异同
590 | *** 拿到命令行参数
591 | #+begin_src sh
592 | version=${1:-"1.4.0"}
593 | mkdir -p atmos-$version
594 | newest_applance=$(ls -Xl atmos-auto-$version* |tail -n 1 |awk '{print $9}')
595 | if [[ ! -f atmos-$version/$newest_applance ]]
596 | then
597 | ln $newest_applance atmos-$version/
598 | fi
599 | echo $newest_applance |cut -d'-' -f3
600 | #+end_src
601 | *** DONE shell: 怎样通过命令行参数把含有回车符的字符串传给python程序
602 | 程序中的\是可以转换了.而传入的参数中的\是不转义的.如果你使用repr()看一下它们的内部表示就知道了:
603 |
604 | 对于传入的"a\nb\n"在python运行时其实是"a\\nb\\n",与内部的"a\nb\n"是不同的.
605 | **** code :noexport:
606 | #+BEGIN_SRC -t
607 | python ttt.py $'a\nb\nc'
608 |
609 | ;; -------------------------- separator --------------------------
610 | [root@mail ~]# A="a
611 | > b
612 | > c
613 | > "
614 | [root@mail ~]# python ttt.py $A
615 | a
616 | b
617 | c
618 | a
619 | a
620 | ;; -------------------------- separator --------------------------
621 | [root@mail ~]# python ttt.py "a
622 | > b
623 | > c
624 | > "
625 | a
626 | b
627 | c
628 | a
629 | b
630 | c
631 |
632 | a
633 | b
634 | c
635 | ;; -------------------------- separator --------------------------
636 | #+END_SRC
637 | **** useful link
638 | http://bbs.chinaunix.net/archiver/tid-913541.html\\
639 | 怎样通过命令行参数把含有回车符"\n"的字符串传给python程序
640 | *** DONE shell中的if是指命令成功执行为真,即$?为0
641 | CLOSED: [2010-03-15 星期一 11:44]
642 | #+BEGIN_EXAMPLE
643 | if fun; then
644 | if [[ $(fun) -ne 1 ]]; then
645 | ;; -------------------------- separator --------------------------
646 |
647 | 如下代码的输出为
648 | here2
649 | here4
650 | here7
651 | ;; -------------------------- separator --------------------------
652 |
653 | function fun()
654 | {
655 | return 1
656 | }
657 | UPGRADE_SKIP_INSTALL="true"
658 | if $UPGRADE_SKIP_INSTALL; then
659 | if fun; then
660 | echo "here1"
661 | else
662 | echo "here2"
663 | fi
664 | else
665 | echo "here3"
666 | fi
667 |
668 | if [[ $(fun) -ne 1 ]]; then
669 | echo "here4"
670 | else
671 | echo "here5"
672 | fi
673 |
674 | if [[ $(fun) == 1 ]]; then
675 | echo "here6"
676 | else
677 | echo "here7"
678 | fi
679 | #+end_example
680 | *** DONE shell的shift命令
681 | CLOSED: [2010-02-26 星期五 15:37]
682 | shift命令指定参数时,会将参量列表左移指定的次数.
683 | 没有给定参数时,shift命令仅把参量列表左移一次.
684 | 一旦列表被移动,左端那个参数就被永远删除了.
685 | ** 变量扩展修饰符 :IMPORTANT:HARD:
686 | http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion
687 |
688 | ${EDITOR:-/bin/vi}
689 |
690 | 修饰符首先提供一个简单的条件测试,用来检查某个变量是否已经被设置,然后根据测试结果给变量赋一个值.
691 | | 修饰符 | 值 |
692 | |----------------------------+-------------------------------------------------------------------------------------------------------------------------------------|
693 | | ${variable:-word} | 如果变量variable已被设置且非空,则代入它的值.否则,代入word |
694 | | ${variable:=word} | 已被设置且值非空,就代入它的值.否则,将variable的值设为word.始终代入varialble的值.位置参量不能用这种方式赋值. |
695 | | ${varialble:+word} | 如果变量variable已被设置且值非空,代入word.否则,什么都 不代入(代入空值) |
696 | | ${varialble:?word} | 如果变量variable已被设置且值非空,就代入它的值.否则,输出word并且从shell退出.如果省略了word,就会显示信息:parameter null or not set |
697 | | ${varialble:offset} | 获得变量variable值中位置从offset开始的子串,偏移为从0到串的末尾. |
698 | | ${varialble:offset:length} | 获得变量variable值中位置从offset开始长度为length的子串. |
699 |
700 | echo $EDITOR
701 |
702 | echo ${EDITOR:-/bin/vi}
703 |
704 | local timeout=${1?"timeout required"} # in second
705 | *** DONE shell语法:local extra_tr=${@:-""} 当参数为空时,赋予默认值
706 | CLOSED: [2010-03-04 星期四 15:11]
707 | *** DONE shell:local ip=${1?} 参数的非空检查
708 | CLOSED: [2010-03-04 星期四 15:10]
709 | **** codesnippet
710 | #+begin_src sh
711 | __mail_subject_prefix="${1?'mail subject prefix required'}"
712 | ;; -------------------------- separator --------------------------
713 | function util_is_ip()
714 | {
715 | local ip=${1?}
716 |
717 | [[ $ip =~ ^<0-9>{1,3}\.<0-9>{1,3}\.<0-9>{1,3}\.<0-9>{1,3}$ ]]
718 | return $?
719 | }
720 | #+end_src
721 | ** 重复执行命令(Event Designators,命令指示符):
722 | | Item | Summary |
723 | |-------------+--------------------------------------------------------|
724 | | !! | 重复执行最近一条命令 |
725 | | !str | 重复执行最近一条以str开头的命令 |
726 | | !?str? | 重复执行最近一条包含str的命令 |
727 | | !N | 重复执行第N条命令 |
728 | | !-N | 重复执行倒数第N条命令 |
729 | | ^str1^str2^ | 重复执行最近一条命令,但将命令中的字符串str1替换为str2 |
730 | ** 示例代码
731 | *** 遍历文件夹
732 | #+begin_src sh
733 | function ergodic(){
734 | for file in ` ls $1 `
735 | do
736 | if [ -d $1"/"$file ]
737 | then
738 | ergodic $1"/"$file
739 | else
740 | echo $1"/"$file
741 | fi
742 | done
743 | }
744 | INIT_PATH="/etc/mysql"
745 | ergodic $INIT_PATH
746 | #+end_src
747 | *** 检查脚本运行用户(是否为root)
748 | #+begin_src sl
749 | check_run_use()
750 | {
751 | if [ "$UID" -ne "$ROOT_UID"]
752 | then
753 | echo "please su to root"
754 | exit 0
755 | fi
756 | }
757 | #+end_src
758 | *** 检查字符串是否为字母
759 | #+begin_src sl
760 | is_alpha()
761 | {
762 | [ $# -eq 1 ] || return $FAILURE
763 |
764 | case $1 in
765 | *[!a-zA-Z]*|"") return $FAILURE
766 | *) return $SUCCESS
767 | esac
768 | }
769 | #+end_src
770 | *** 把传递字符串修改为小写
771 | #+begin_src sl
772 | to_lower()
773 | {
774 | if [ -z "$1" ]
775 | then
776 | echo "(null)"
777 | return
778 | fi
779 | echo "$@" | tr A-Z a-z
780 | return
781 | }
782 | #+end_src
783 | *** 完整模板示例 :noexport:
784 | #+begin_src sh
785 | #filename
786 | #author : tito
787 | #email : tito@shopex.cn
788 | #since : 2009-1-11
789 | #modify : 2009-1-12
790 | #deploy : 124.74.193.211
791 | #function : clean log dirtory
792 |
793 | log_dir="/var/log/httpd"
794 | this_date=`date +'%Y%m%d'`
795 | back_file_name="back."this_date".tar.gz"
796 | #clean up dir
797 | clean_up_dir(){
798 | #$1 is enter dirctory
799 | if [ -d "$1" ]
800 | then
801 | echo "$1 is not a dictory"
802 | exit 0
803 | fi
804 | cd $1
805 | #back up the log file
806 | tar -zxvf $back_file_name $1/*
807 | cp $back_file_name /opt
808 | #rm the log file in is dictory
809 | rm -f "$1/*"
810 | return 0
811 | }
812 |
813 | clean_up_dir() $log_dir
814 |
815 | exit 0
816 | #+end_src
817 | *** 检查参数
818 | #+begin_src sl
819 | #check enter args
820 | usage ()
821 | {
822 | if [ -z "$1" ]
823 | then
824 | msg=filename
825 | else
826 | msg=$@
827 | fi
828 |
829 | echo "`basename $0`"$msg""
830 | }
831 | #+end_src
832 | *** DONE shell 如何打印出标准错误输出后, 退出
833 | CLOSED: [2011-01-27 Thu 20:37]
834 | #+begin_src sh
835 | out=$(ssh_do $master_node_ip $cmd || {
836 | log_error " Failed to sync time of maui nodes."
837 | return 1
838 | }
839 | )
840 | #+end_src
841 | *** DONE [#A] shell中, 如何向文件中添加一行, 如果该行已经存在, 则不添加
842 | CLOSED: [2011-10-13 Thu 16:43]
843 | #+BEGIN_EXAMPLE
844 | - 保证./test.cfg中, key1的值为value1, 如果key1不存在, 则追加一行key1 = value1
845 | (grep "key1 \+=" ./test.cfg && sudo sed -i 's/key1 \+=.*/key1 = value1/' ./test.cfg) || ((cat ./test.cfg; echo "key1 = value1") | sudo tee ./test.cfg)
846 | # --8<-------------------------- §separator§ ------------------------>8--
847 |
848 | sudo sed -i 's/xmodmap ~\/.xmodmap 2>\/dev\/null//' /tmp/hosts
849 |
850 | echo xmodmap ~/.xmodmap 2>/dev/null | sudo tee /tmp/hosts
851 |
852 | sudo sed -i 's/xmodmap ~\/.xmodmap 2>\/dev\/null//' /tmp/hosts
853 | #+end_example
854 | *** DONE shell中function使用返回值 - return/echo
855 | CLOSED: [2010-03-04 星期四 11:09]
856 | increment(){
857 | sum=`expr $1 + 1`
858 | return $sum
859 | }
860 |
861 | echo -n "This sum is "
862 | increment 5
863 |
864 | echo $?
865 | echo $sum
866 |
867 | 变量sum虽然是在函数increment中定义的,但它的作用域却是全局的.
868 | 因而可以在调用函数的脚本中被识别.
869 | *** 逻辑与的示例代码
870 | #+begin_src sh
871 | if test -d /home -a -d /tmp2 ; then
872 | echo "two directories exist"
873 | else
874 | echo "don't exist"
875 | fi;
876 | #+end_src
877 | ** basic use
878 | *** DONE 单引号内不被解释,双引号内会被解释
879 | CLOSED: [2010-03-04 星期四 13:33]
880 | #+BEGIN_EXAMPLE
881 | 单引号能保护所有元字符不被解释.
882 | 双引号允许对它所括的内容进行变量替换和命令替换.
883 |
884 | echo Don\'t you need '$5.00?'
885 | echo 'Mother yelled, "Time to eat!"'
886 |
887 | name=Jody
888 | echo "Hi $name, I'm glad to meet you!"
889 | echo "Hey $name, the time is $(date)"
890 |
891 | 创建脚本时,脚本的第一行通常称为shbang(#!)行.
892 | 当脚本启动后,UNIX内核检查文件的第一行以决定将要执行的程序类型.
893 | #+end_example
894 | *** DONE shell调试:set -x开启echo, sh -n解释不执行命令
895 | CLOSED: [2010-03-04 星期四 15:39]
896 | | 命令 | 选项 | 含义 |
897 | | sh -x scriptname | Echo选项 | 在变量替换之后,执行之前显示脚本的每一行 |
898 | | sh -v scriptname | Verbose选项 | 执行之前显示脚本的每一行,与键入脚本中的一样 |
899 | | sh -n scriptname | Noexec选项 | 解释但不执行命令 |
900 | | set -u | 未绑定变量 | 尚未设置的标志变量 |
901 | | set -x | 开启echo | 跟踪脚本执行 |
902 | | set +x | 关闭echo | 关闭跟踪 |
903 | ** useful link
904 | http://www.hsrl.rutgers.edu/ug/shell_help.html\\
905 | How to write a shell script
906 | http://www.freeos.com/guides/lsst/\\
907 | Linux Shell Scripting Tutorial v1.05r3
908 | http://www.cyberciti.biz/tips/how-to-generating-print-range-sequence-of-numbers.html#comments\\
909 | Shell Scripting: Generate or Print Range of Numbers ( Sequence of Numbers for Loop )
910 | ** DONE Shell: Argument list too long
911 | CLOSED: [2011-01-27 Thu 22:58]
912 | #+begin_example
913 | http://www.linuxjournal.com/article/6060\\
914 | "Argument list too long": Beyond Arguments and Limitations | Linux Journal
915 | http://richmegginson.livejournal.com/11296.html\\
916 | richmegginson: Fun with bourne shell: Argument list too long
917 | http://en.kioskea.net/faq/1086-unable-to-delete-file-argument-list-too-long\\
918 | Unable to delete file: language.org
919 | http://www.unix.com/shell-programming-scripting/25666-argument-list-too-long-shell-error.html\\
920 | Argument list too long - Shell error - The UNIX and Linux Forums
921 | #+end_example
922 | ** CANCELED Why below shell script fail :noexport:
923 | CLOSED: [2011-03-02 Wed 13:34]
924 | To trigger the recovery proces, please run below command for each SS disk in this node:
925 | mauisvcmgr -s mauicc -c trigger_cc_rcvrtask -a 'queryStr=:,act=DiskRecover,taskId='
926 |
927 | replace with the name of the node.
928 | replace with the id of the SS disk -- the id is order of the output "grep mauiss /etc/fstab", starting from 1.
929 | replace with a random UUID -- you can generate it from uuidgen.
930 |
931 | Denny, could you help to write a shell script to automate this step? Thanks.
932 | *** code snippet :noexport:
933 | #!/bin/sh
934 | # Trigger cc recovery task in all SS disk of current node
935 | current_hostname=`hostname`
936 | disk_id=1
937 | # Iterate each ss disk
938 | ss_disk_count=`grep mauiss /etc/fstab | wc -l`
939 | for ss_disk in $(seq $ss_disk_count); do
940 | random_uuid=`uuidgen`
941 | echo "mauisvcmgr -s mauicc -c trigger_cc_rcvrtask -a 'queryStr=$current_hostname:$disk_id,act=DiskRecover,taskId=$random_uuid'"
942 | mauisvcmgr -s mauicc -c trigger_cc_rcvrtask -a 'queryStr=$current_hostname:$disk_id,act=DiskRecover,taskId=$random_uuid'
943 | disk_id=`expr $disk_id + 1`
944 | echo "========="
945 | done
946 | echo "Finish of the script"
947 | ** shell function sample
948 | #+begin_src sh
949 | #!/bin/sh
950 | srv_name=${1?"service name required"}
951 | node_name=${2?"node name required"}
952 | srv_port=${3?"service port required"}
953 | function create_zk_node()
954 | {
955 | local path=${1?}
956 | local data=${2?}
957 | zk_tool -c query -p $path || zk_tool -c create -p $path -d $data
958 | }
959 | create_zk_node "/services" "service"
960 | create_zk_node "/services/${srv_name}" "service"
961 | create_zk_node "/services/${srv_name}/instances" "instances"
962 | create_zk_node "/services/${srv_name}/global_conf" "global_conf"
963 | create_zk_node "/services/${srv_name}/global_conf/port" $srv_port
964 | create_zk_node "/services/${srv_name}/instances/${node_name}" "instance"
965 | create_zk_node "/services/${srv_name}/instances/${node_name}/instance_conf" "instance"
966 | #+end_src
967 | ** DONE [#A] sample: shell on-line help
968 | CLOSED: [2012-03-28 Wed 11:49]
969 | *** console shot: :noexport:
970 | #+begin_example
971 | ///52f4795d9c60ad26bf18beed5c43d11b#$cat /usr/local/bin/thrift_client
972 | #!/bin/bash
973 |
974 | PWD=/usr/local/sanity/lib/sanity-1
975 | NODE_NAME="$(basename $0 .sh)"
976 | VERSION=1.0
977 |
978 | check()
979 | {
980 | exec erl -noshell -noinput -pa "$PWD/ebin" \
981 | +fnu \
982 | +K true \
983 | -setcookie random \
984 | -s sanity_checker $1 $2 $3
985 | }
986 |
987 | usage()
988 | {
989 | echo "${NODE_NAME}: missing argument
990 | Try \`${NODE_NAME} --help' for more information."
991 | exit 0
992 | }
993 |
994 | help()
995 | {
996 | cat <8--
1058 | ** TODO shell将如下代码定义成函数
1059 | #+begin_src sh
1060 | while [ -z "$all_servers" ] ; do
1061 | echo -ne "Enter the ip list for all nodes in the system, separated by whitespace. Sample: 192.168.75.101 192.168.75.102\n> "
1062 | read -e all_servers
1063 | update_option_in_conf "$System_file" "all_servers" "$all_servers"
1064 | done
1065 | #+end_src
1066 | ** TODO shell为什么没有方便的自增
1067 | ///0352ea91def77fd8e5d305f770ca1f70#$failure=0
1068 | ///0352ea91def77fd8e5d305f770ca1f70#$failure=`expr $failure + 1`
1069 | ** TODO Linux exec command
1070 | http://www.linuxjournal.com/content/bash-redirections-using-exec\\
1071 | Bash Redirections Using Exec | Linux Journal
1072 | *** code
1073 | src/mgmt/tools/pgdbsetup
1074 | #+BEGIN_SRC -t
1075 | sub closeMongrelFd
1076 | {
1077 | my @res = `lsof -i TCP:3000 | grep mongrel | awk '{print \$4}' | sed 's/[a-zA-Z]//'`;
1078 | my $mongrelFd = $res[0];
1079 | chomp ($mongrelFd);
1080 | if($mongrelFd)
1081 | {
1082 | my $cmd = "exec $mongrelFd>&-";
1083 | print $cmd;
1084 | `$cmd`
1085 | }
1086 | }
1087 | #+END_SRC
1088 | *** code
1089 | /tmp/tmp:
1090 |
1091 | apples
1092 | pears
1093 | bananas
1094 | pleaches
1095 | plums
1096 | #+BEGIN_SRC -t
1097 | #!/bin/sh
1098 | # Scriptname: speller
1099 | # Purpose: Check and fix spelling errors in a file
1100 | exec < /tmp/tmp
1101 | while read line
1102 | do
1103 | echo $line
1104 | echo -n "Is this word correct? [ Y/N]"
1105 | read answer < /dev/tty
1106 | case "$answer" in
1107 | [Yy]* )
1108 | continue;;
1109 | *)
1110 | echo "What is the correct spelling?"
1111 | read word < /dev/tty
1112 | sed "s/$line/$word/g" /tmp/tmp >error
1113 | mv error tmp
1114 | echo $line has been changed to $word.
1115 | esac
1116 | done
1117 | #+END_SRC
1118 | *** TODO Shell: Exec命令
1119 | #+BEGIN_EXAMPLE
1120 | 使用exec命令,不需要创建子shell,就能打开或关闭标准输入和标准输出.
1121 |
1122 | exec命令常被用来打开文件(根据文件名或文件描述符)以供读写.注意,文件描述符0,1和2已预留
1123 | 给标准输入`标准输出和标准错误输出.文件打开后,将得到下一个可用的文件描述符.
1124 | #+end_example
1125 | ** TODO shell中. ./1.sh与sh ./1.sh的区别是什么
1126 | ** CDPATH: 对于访问经常去的目录, 节省cd输入目录路的时间
1127 | ** How to find the length of a variable
1128 | http://unix-school.blogspot.in/2010_04_01_archive.html\\
1129 | | Item | Summary |
1130 | |--------------------------------------------------------+---------|
1131 | | echo ${#VAR} | |
1132 | | echo -n $VAR | wc -c | |
1133 | | printf $VAR | wc -c | |
1134 | | expr $VAR : '.*' | |
1135 | | echo $VAR | awk '{print length ;}' | |
1136 | | echo $VAR | perl -ne 'chop; print length($_) . "\n";' | |
1137 | ** [#A] shell的启动配置文件执行顺序 :IMPORTANT:
1138 | http://zhidao.baidu.com/question/366827280.html
1139 | #+begin_example
1140 | ~/.bash_profile 是交互式`login 方式进入 bash 运行的
1141 | ~/.bashrc 是交互式 non-login 方式进入 bash 运行的
1142 | shell的分类:
1143 | 交互式登录shell:以一个用户的身份登陆进去,输入命令的格式的shell
1144 | 读取配置文件的顺序:
1145 | /etc/profile-->/etc/profile.d/*-->~/.bash_profile-->~/.bashrc-->/etc/bashrc
1146 | 非交互式登录shell:只在一个脚本的,不需要用户登录,自动运行
1147 | 读取配置文件的顺序:
1148 | /.bashrc-->/etc/bashrc-->/etc/profile.d/*
1149 | #+end_example
1150 | ** TODO shell输出多行内容时的重定向
1151 | ** TODO shell hook函数, 在返回时调用一个方法
1152 | ** su命令和su -命令的区别
1153 | http://www.ha97.com/4001.html
1154 | #+begin_example
1155 | su命令和su -命令最大的本质区别就是:前者只是切换了root身份,但Shell环境
1156 | 仍然是普通用户的Shell;而后者连用户和Shell环境一起切换成root身份了.只
1157 | 有切换了Shell环境才不会出现PATH环境变量错误.su切换成root用户以后,pwd
1158 | 一下,发现工作目录仍然是普通用户的工作目录;而用su -命令切换以后,工作
1159 | 目录变成root的工作目录了.用echo $PATH命令看一下su和su -以后的环境变量
1160 | 有何不同.以此类推,要从当前用户切换到其它用户也一样,应该使用su -命令
1161 | #+end_example
1162 | ** [ -e /etc/*.conf ] 是不正确的,如果是判断满足某个pattern的文件是否存在,需要用find -name来查找
1163 | ** [#A] bash执行带单引号的命令, $command方式是不行的,需要用eval $command :IMPORTANT:
1164 | ** Here document 是 shell 的一个非常常用的功能: << EOF ... EOF
1165 | http://ylinux.org/246
1166 | #+begin_example
1167 | 如何结束字符用引号括起来,那么 Here 文档中的变量是不会被替换的:
1168 | $ cat > /tmp/t_here.txt << "EOF"
1169 | UID=$UID
1170 | EOF
1171 | $ cat /tmp/t_here.txt
1172 | UID=$UID
1173 |
1174 | 如果结束字符没有用引号括起来:
1175 |
1176 | $ cat > /tmp/t_here.txt << EOF
1177 | UID=$UID
1178 | EOF
1179 | $ cat /tmp/t_here.txt
1180 | UID=1000
1181 |
1182 | #+end_example
1183 | ** 判断数据类型为int
1184 | #+begin_src sh
1185 | ,-----------
1186 | | @@ -91,7 +91,7 @@
1187 | | print_testcase_info "$testcase_name" "$testcase_desc"
1188 | | show_output="t"
1189 | | result=$(remote_command $hostname "ps -ef | grep '$process_regex' | grep -v grep | awk -F' ' '{print \$2}' | xargs ps -o vsz= -p")
1190 | | - if [ $? -ne 0 ]; then
1191 | | + if [ $? -ne 0 ] || [ -z "${result##*[!0-9]*}" ]; then
1192 | | log_failure "$scenario_name" "$testcase_name" \
1193 | | "Output:($result), Fail to get memory for ($process_regex) in ($hostname).\n\n"
1194 | | else
1195 | `-----------
1196 | #+end_src
1197 | ** [#B] on-line help usage
1198 | #+begin_src sh
1199 | #!/bin/bash
1200 | ##-------------------------------------------------------------------
1201 | ## @copyright 2013
1202 | ## File : xzb_update_user_html.sh
1203 | ## Author : filebat
1204 | ## Description : Update posts info to mysql
1205 | ## --
1206 | ## Created : <2013-01-31>
1207 | ## Updated: Time-stamp: <2013-01-31 20:08:58>
1208 | ##-------------------------------------------------------------------
1209 | . ./utility_xzb.sh
1210 |
1211 | BIN_NAME="$(basename $0 .sh)"
1212 |
1213 | function update_user_html() {
1214 | user_dir=${1?"user website directory is required"}
1215 | userid=${2?"userid is required"}
1216 |
1217 | ## TODO automatically get date, since this may not be mandotary
1218 | date=${3?"date is required"}
1219 | index_html="$user_dir/$(echo $date | tr -d -).html"
1220 |
1221 | python_script="import jinja_html; jinja_html.generate_list_user_post(\"$userid\", \"$date\", \"$index_html\")"
1222 |
1223 | command="(cd $XZB_HOME/code/smarty_html; python -c '${python_script}')"
1224 | eval $command
1225 | if [ $? -ne 0 ]; then
1226 | log "[$BIN_NAME.sh] Generate $index_html failed."
1227 | exit 1
1228 | else
1229 | log "[$BIN_NAME.sh] Generate $index_html is done."
1230 | fi
1231 |
1232 | python_script="import jinja_html; jinja_html.generate_user_all_posts(\"$userid\", \"$date\", \"$user_dir\")"
1233 | command="(cd $XZB_HOME/code/smarty_html; python -c '${python_script}')"
1234 | eval $command
1235 | if [ $? -ne 0 ]; then
1236 | log "[$BIN_NAME.sh] Generate html files of user posts failed."
1237 | exit 1
1238 | else
1239 | log "[$BIN_NAME.sh] Generate html files of user posts is done."
1240 | fi
1241 | }
1242 |
1243 | ensure_variable_isset
1244 | ensure_is_root
1245 |
1246 | VERSION=0.1
1247 |
1248 | help()
1249 | {
1250 | cat <13693660985881769154217771468" "http://0.0.0.0:8090/api?signature=7d0e888df44def04c76084d26e92c59fb15c1a50×tamp=1369459087&nonce=1369763244" 2>/dev/null
1369 | bash: ![CDATA[gh_05d5313dea46]]: event not found
1370 | ** DONE bash fail to concat |
1371 | CLOSED: [2013-06-13 Thu 15:09]
1372 | 把${command_str}改在eval $command_str
1373 | *** code
1374 | #+begin_src sh
1375 | command_str="ls | grep a"
1376 | echo "$command_str"
1377 | ${command_str}
1378 | #+end_src
1379 | **** console output
1380 | #+begin_example
1381 | bash-3.2$ sh ./test.sh
1382 | ls | grep a
1383 | ls: a: No such file or directory
1384 | ls: grep: No such file or directory
1385 | ls: |: No such file or directory
1386 | #+end_example
1387 | ** shell include with relateive direction: . $(dirname $0)/utility_xzb.sh
1388 | . $(dirname $0)/utility_xzb.sh
1389 | ** TODO bash -c 调用是什么意思
1390 | ** check whether variable is set
1391 | https://github.com/openstack-dev/devstack.git --> functions
1392 | #+begin_src sh
1393 | function is_set() {
1394 | local var=\$"$1"
1395 | eval "[ -n \"$var\" ]" # For ex.: sh -c "[ -n \"$var\" ]" would be better, but several exercises depends on this
1396 | }
1397 |
1398 | # Prints backtrace info
1399 | # filename:lineno:function
1400 | function backtrace {
1401 | local level=$1
1402 | local deep=$((${#BASH_SOURCE[@]} - 1))
1403 | echo "[Call Trace]"
1404 | while [ $level -le $deep ]; do
1405 | echo "${BASH_SOURCE[$deep]}:${BASH_LINENO[$deep-1]}:${FUNCNAME[$deep-1]}"
1406 | deep=$((deep - 1))
1407 | done
1408 | }
1409 |
1410 | function die() {
1411 | local exitcode=$?
1412 | set +o xtrace
1413 | local line=$1; shift
1414 | if [ $exitcode == 0 ]; then
1415 | exitcode=1
1416 | fi
1417 | backtrace 2
1418 | err $line "$*"
1419 | exit $exitcode
1420 | }
1421 | # Prints line number and "message" in error format
1422 | # err $LINENO "message"
1423 | function err() {
1424 | local exitcode=$?
1425 | errXTRACE=$(set +o | grep xtrace)
1426 | set +o xtrace
1427 | local msg="[ERROR] ${BASH_SOURCE[2]}:$1 $2"
1428 | echo $msg 1>&2;
1429 | if [[ -n ${SCREEN_LOGDIR} ]]; then
1430 | echo $msg >> "${SCREEN_LOGDIR}/error.log"
1431 | fi
1432 | $errXTRACE
1433 | return $exitcode
1434 | }
1435 |
1436 | function die_if_not_set() {
1437 | local exitcode=$?
1438 | FXTRACE=$(set +o | grep xtrace)
1439 | set +o xtrace
1440 | local line=$1; shift
1441 | local evar=$1; shift
1442 | if ! is_set $evar || [ $exitcode != 0 ]; then
1443 | die $line "$*"
1444 | fi
1445 | $FXTRACE
1446 | }
1447 |
1448 | die_if_not_set $LINENO AMI "Failure registering"
1449 | #+end_src
1450 | ** DONE shell script to update ini/cfg configuration file
1451 | CLOSED: [2013-10-22 Tue 14:35]
1452 | /Users/mac/backup/tech/large_sourcecode/openstack/openstack-dev/devstack/openstack-dev/functions
1453 | #+begin_src sh
1454 | # Set an option in an INI file
1455 | # iniset config-file section option value
1456 | function iniset() {
1457 | local file=$1
1458 | local section=$2
1459 | local option=$3
1460 | local value=$4
1461 |
1462 | if ! grep -q "^\[$section\]" "$file" 2>/dev/null; then
1463 | # Add section at the end
1464 | echo -e "\n[$section]" >>"$file"
1465 | fi
1466 | if ! ini_has_option "$file" "$section" "$option"; then
1467 | # Add it
1468 | sed -i -e "/^\[$section\]/ a\\
1469 | $option = $value
1470 | " "$file"
1471 | else
1472 | # Replace it
1473 | sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=[ \t]*\).*$|\1$value|" "$file"
1474 | fi
1475 | }
1476 |
1477 | #+end_src
1478 | ** DONE shell $SECONDS show how long the script runs: echo_summary "stack.sh completed in $SECONDS seconds."
1479 | CLOSED: [2013-10-22 Tue 14:56]
1480 | *** built-in environment: $SECONDS
1481 | stack.sh completed in $SECONDS seconds.
1482 | *** manual caculate
1483 | /Users/mac/backup/tech/large_sourcecode/openstack/openstack-dev/devstack/openstack-dev/exercises/volumes.sh
1484 | #+begin_src sh
1485 | start_time=$(date +%s)
1486 | cinder create --display_name $VOL_NAME --display_description "test volume: $VOL_NAME" $DEFAULT_VOLUME_SIZE || \
1487 | die $LINENO "Failure creating volume $VOL_NAME"
1488 | if ! timeout $ACTIVE_TIMEOUT sh -c "while ! cinder list | grep $VOL_NAME | grep available; do sleep 1; done"; then
1489 | die $LINENO "Volume $VOL_NAME not created"
1490 | fi
1491 | end_time=$(date +%s)
1492 | echo "Completed cinder create in $((end_time - start_time)) seconds"
1493 |
1494 | #+end_src
1495 | ** shell function in function
1496 | /Users/mac/backup/tech/large_sourcecode/openstack/openstack-dev/devstack/openstack-dev/lib/swift
1497 | #+begin_src sh
1498 | function test() {
1499 | function test1() {
1500 | echo "hello1"
1501 | }
1502 | test1
1503 | test1
1504 | test1
1505 | test1
1506 | }
1507 | test
1508 | test1
1509 | echo "end"
1510 | #+end_src
1511 | ** DONE grep command output: make sure detect the command is running correctly
1512 | CLOSED: [2013-10-22 Tue 16:42]
1513 | *** 方法:
1514 | #+begin_example
1515 | val=$(nova aggregate-list | grep -c " $aggregate_name ")
1516 | if [[ $? -eq 0 ]] && [[ $val == 0 ]]; then
1517 | #+end_example
1518 | *** 相关信息
1519 | https://review.openstack.org/#/c/53233/1/exercises/aggregates.sh,unified
1520 | #+begin_example
1521 |
1522 | diff --git a/exercises/aggregates.sh b/exercises/aggregates.sh
1523 | index e5fc7de..f8c60f9 100755
1524 | --- a/exercises/aggregates.sh
1525 | +++ b/exercises/aggregates.sh
1526 | @@ -48,24 +48,25 @@
1527 | 48 48 # Create an aggregate
1528 | 49 49 # ===================
1529 | 50 50
1530 | 51 51 AGGREGATE_NAME=test_aggregate_$RANDOM
1531 | 52 52 AGGREGATE2_NAME=test_aggregate_$RANDOM
1532 | 53 53 AGGREGATE_A_ZONE=nova
1533 | 54 54
1534 | 55 55 exit_if_aggregate_present() {
1535 | 56 56 aggregate_name=$1
1536 | 57 57
1537 | 58 - if [ $(nova aggregate-list | grep -c " $aggregate_name ") == 0 ]; then
1538 | 58 + val=$(nova aggregate-list | grep -c " $aggregate_name ")
1539 | 59 + if [[ $? -eq 0 ]] && [[ $val == 0 ]]; then
1540 | 59 60 echo "SUCCESS $aggregate_name not present"
1541 | 60 61 else
1542 | 61 - die $LINENO "found aggregate: $aggregate_name"
1543 | 62 + die $LINENO "fail to get aggregate or found aggregate: $aggregate_name"
1544 | 62 63 exit -1
1545 | 63 64 fi
1546 | 64 65 }
1547 | 65 66
1548 | 66 67 exit_if_aggregate_present $AGGREGATE_NAME
1549 | 67 68
1550 | 68 69 AGGREGATE_ID=$(nova aggregate-create $AGGREGATE_NAME $AGGREGATE_A_ZONE | grep " $AGGREGATE_NAME " |
1551 | get_field 1)
1552 | 69 70 AGGREGATE2_ID=$(nova aggregate-create $AGGREGATE2_NAME $AGGREGATE_A_ZONE | grep " $AGGREGATE2_NAME "
1553 | | get_field 1)
1554 | 70 71
1555 | 71 72 # check aggregate created
1556 | #+end_example
1557 | ** DONE shell contiune loop
1558 | CLOSED: [2013-10-23 Wed 15:25]
1559 | http://www.cyberciti.biz/faq/unix-linux-bsd-appleosx-continue-in-bash-loop/
1560 | #+begin_src sh
1561 | for i in something
1562 | do
1563 | [ condition ] && continue
1564 | cmd1
1565 | cmd2
1566 | done
1567 | #+end_src
1568 | ** DONE trueorfalse
1569 | CLOSED: [2013-10-23 Wed 15:29]
1570 | /Users/mac/backup/tech/large_sourcecode/openstack/openstack-dev/devstack/is-service-enabled/functions
1571 | #+begin_src sh
1572 | # Normalize config values to True or False
1573 | # Accepts as False: 0 no No NO false False FALSE
1574 | # Accepts as True: 1 yes Yes YES true True TRUE
1575 | # VAR=$(trueorfalse default-value test-value)
1576 | function trueorfalse() {
1577 | local default=$1
1578 | local testval=$2
1579 |
1580 | [[ -z "$testval" ]] && { echo "$default"; return; }
1581 | [[ "0 no No NO false False FALSE" =~ "$testval" ]] && { echo "False"; return; }
1582 | [[ "1 yes Yes YES true True TRUE" =~ "$testval" ]] && { echo "True"; return; }
1583 | echo "$default"
1584 | }
1585 | #+end_src
1586 | ** DONE bash backtrace
1587 | CLOSED: [2013-10-23 Wed 16:12]
1588 | /Users/mac/backup/tech/large_sourcecode/openstack/openstack-dev/devstack/openstack-dev/functions
1589 | #+begin_src sh
1590 | # Prints backtrace info
1591 | # filename:lineno:function
1592 | function backtrace {
1593 | local level=$1
1594 | local deep=$((${#BASH_SOURCE[@]} - 1))
1595 | echo "[Call Trace]"
1596 | while [ $level -le $deep ]; do
1597 | echo "${BASH_SOURCE[$deep]}:${BASH_LINENO[$deep-1]}:${FUNCNAME[$deep-1]}"
1598 | deep=$((deep - 1))
1599 | done
1600 | }
1601 | #+end_src
1602 | ** DONE detech oom-killer
1603 | CLOSED: [2013-10-30 Wed 19:05]
1604 | /Users/mac/backup/tech/large_sourcecode/openstack/openstack-infra/config/modules/jenkins/files/slave_scripts/jenkins-oom-grep.sh
1605 | #+begin_src sh
1606 | #!/bin/bash
1607 |
1608 | # Copyright 2012 Hewlett-Packard Development Company, L.P.
1609 | #
1610 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
1611 | # not use this file except in compliance with the License. You may obtain
1612 | # a copy of the License at
1613 | #
1614 | # http://www.apache.org/licenses/LICENSE-2.0
1615 | #
1616 | # Unless required by applicable law or agreed to in writing, software
1617 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1618 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1619 | # License for the specific language governing permissions and limitations
1620 | # under the License.
1621 |
1622 | # Find out if jenkins has triggered the out-of-memory killer by checking
1623 | # the output of dmesg before and after a test run.
1624 |
1625 | PATTERN=" invoked oom-killer: "
1626 |
1627 | case "$1" in
1628 | pre)
1629 | rm -fr /tmp/jenkins-oom-log
1630 | mkdir /tmp/jenkins-oom-log
1631 | dmesg > /tmp/jenkins-oom-log/pre
1632 | exit 0
1633 | ;;
1634 | post)
1635 | dmesg > /tmp/jenkins-oom-log/post
1636 | diff /tmp/jenkins-oom-log/{pre,post} \
1637 | | grep "^> " | sed "s/^> //" > /tmp/jenkins-oom-log/diff
1638 | if grep -q "$PATTERN" /tmp/jenkins-oom-log/diff
1639 | then
1640 | cat /tmp/jenkins-oom-log/diff
1641 | exit 1
1642 | fi
1643 | ;;
1644 | esac
1645 |
1646 | #+end_src
1647 | ** DONE shell:当$(fun)方式调用时,fun没法quit 当前shell script
1648 | CLOSED: [2013-12-12 Thu 20:59]
1649 | #+begin_src sh
1650 | get_data() {
1651 | local match_column=$(($1 + 1))
1652 | local regex="$2"
1653 | local output_column=$(($3 + 1))
1654 | shift 3
1655 |
1656 | result=$("$@" | \
1657 | awk -F'|' \
1658 | "! /^\+/ && \$${match_column} ~ \"^ *${regex} *\$\" \
1659 | { print \$${output_column} }")
1660 | [[ -z "$result" ]] || exit -1
1661 | }
1662 |
1663 | output=$(get_data 2 admin 1 keystone role-list)
1664 | echo $output
1665 | #+end_src
1666 | ** TODO awk "length>50" /home/zhangwei/elmar/elmar/src/elmar.erl打印出文件名与行号数
1667 | ** DONE ask for confirmation
1668 | CLOSED: [2013-12-31 Tue 23:59]
1669 | #+begin_src sh
1670 | #!/bin/bash
1671 | ##-------------------------------------------------------------------
1672 | ## File : test.sh
1673 | ## Author : filebat
1674 | ## Description :
1675 | ## --
1676 | ## Created : <2013-12-29>
1677 | ## Updated: Time-stamp: <2013-12-31 23:58:24>
1678 | ##-------------------------------------------------------------------
1679 | if [ "$1" = "-y" ] || [ "$1" = "--yes" ]; then
1680 | SKIP_ASK=y
1681 | shift
1682 | fi
1683 |
1684 | user_wants() {
1685 | if [ "$SKIP_ASK" = "y" ]; then return 0; fi
1686 |
1687 | while true; do
1688 | read -n 1 -p "$1 " cont
1689 | echo 1>&2
1690 | case $cont in
1691 | y|Y)
1692 | return 0
1693 | ;;
1694 | n|N)
1695 | return 1
1696 | ;;
1697 | *)
1698 | ;;
1699 | esac
1700 | done
1701 | }
1702 |
1703 | if user_wants 'Drop Heat database tables?'; then
1704 | echo "here"
1705 | fi
1706 |
1707 | ## File : test.sh ends
1708 |
1709 | #+end_src
1710 | ** DONE sh wrap OS difference
1711 | CLOSED: [2014-01-01 Wed 00:17]
1712 | /Users/mac/backup/tech/large_sourcecode/openstack/openstack/heat/heat/bin/heat-db-setup
1713 | #+begin_src sh
1714 | # Check for root privileges
1715 | if [[ $EUID -ne 0 ]] ; then
1716 | echo "This operation requires superuser privileges, using sudo:"
1717 | if sudo -l > /dev/null ; then
1718 | ELEVATE="sudo"
1719 | else
1720 | exit 1
1721 | fi
1722 | fi
1723 |
1724 | case "$1" in
1725 | rpm)
1726 | echo "Installing on an RPM system."
1727 | PACKAGE_INSTALL="$ELEVATE yum install"
1728 | PACKAGE_STATUS="rpm -q"
1729 | SERVICE_MYSQLD="mysqld"
1730 | SERVICE_START="$ELEVATE service $SERVICE_MYSQLD start"
1731 | SERVICE_STATUS="service $SERVICE_MYSQLD status"
1732 | SERVICE_ENABLE="$ELEVATE chkconfig"
1733 | ;;
1734 | deb)
1735 | echo "Installing on a Debian system."
1736 | PACKAGE_INSTALL="$ELEVATE apt-get install"
1737 | PACKAGE_STATUS="dpkg-query -s"
1738 | SERVICE_MYSQLD="mysql"
1739 | SERVICE_START="$ELEVATE service $SERVICE_MYSQLD start"
1740 | SERVICE_STATUS="$ELEVATE service $SERVICE_MYSQLD status"
1741 | SERVICE_ENABLE=""
1742 | ;;
1743 | *)
1744 | usage
1745 | ;;
1746 | esac
1747 |
1748 | #+end_src
1749 | ** DONE sh check for root privileges, since the euid may not be 0, but still in the admin user group
1750 | CLOSED: [2014-01-01 Wed 00:19]
1751 | #+begin_src sh
1752 | # Check for root privileges
1753 | if [[ $EUID -ne 0 ]] ; then
1754 | echo "This operation requires superuser privileges, using sudo:"
1755 | if sudo -l > /dev/null ; then
1756 | ELEVATE="sudo"
1757 | else
1758 | exit 1
1759 | fi
1760 | fi
1761 |
1762 | #+end_src
1763 | ** DONE shell comparision of float
1764 | CLOSED: [2014-07-10 Thu 10:11]
1765 | http://stackoverflow.com/questions/11541568/how-to-do-float-comparison-in-bash
1766 | echo "10.2>10.1" | bc
1767 | ** run_command_in_all_nodes.sh
1768 | #+begin_src sh
1769 | #!/bin/bash
1770 | ##-------------------------------------------------------------------
1771 | ## File : run_command_in_all_nodes.sh
1772 | ## Author : Denny
1773 | ## Description : Run command in a list of servers.
1774 | ## Here we assume ssh key is properly uploaded, thus we
1775 | ## don't need to input ssh password
1776 | ## --
1777 | ## Created : <2014-07-10>
1778 | ## Updated: Time-stamp: <2014-07-31 14:10:04>
1779 | ##-------------------------------------------------------------------
1780 |
1781 | # Example1: Run a command in all nodes of prod env.
1782 | # sh ./run_command_in_all_nodes.sh "ssh root@HOSTIP date"
1783 | # Note: We assume ssh public key is uploaded properly
1784 | # In above, HOSTIP will be replaced by server ip.
1785 | #
1786 | # Example2: Run a command in some nodes
1787 | # sh ./run_command_in_all_nodes.sh "ssh root@HOSTIP date" "172.20.16.14 172.20.16.12"
1788 |
1789 | command=${1:-"ssh root@HOSTIP date"}
1790 | server_list=${2:-"172.20.16.14 172.20.16.12 172.20.16.17 172.20.16.18 172.20.16.13 172.20.16.15 172.20.16.16 172.20.16.11 172.21.16.11 172.21.16.12 172.20.16.19 172.20.16.20 172.20.16.23 172.20.16.26 172.20.18.13 172.20.18.15 172.20.18.16"}
1791 |
1792 | date=`date +%Y-%m-%d_%H:%M`
1793 | has_error=false
1794 | echo `date +['%Y-%m-%d %H:%M:%S']` "Actions Begin\n"
1795 |
1796 | for server in ${server_list[*]}; do
1797 | actual_command=`echo $command | sed "s/HOSTIP/$server/g"`
1798 | echo "\n========== On $server Run: $actual_command =========="
1799 | output=`$actual_command`
1800 | if [ $? -ne 0 ]; then
1801 | has_error=true
1802 | echo "Error to run: $actual_command\n"
1803 | else
1804 | if (echo "$output" | grep -i error 1>/dev/null); then
1805 | has_error=true
1806 | echo "========== Action on $server failed =========="
1807 | fi;
1808 | fi;
1809 | echo "${output}\n"
1810 | done;
1811 |
1812 | echo `date +['%Y-%m-%d %H:%M:%S']`" Actions are done\n"
1813 | ## File : run_command_in_all_nodes.sh ends
1814 | #+end_src
1815 | ** DONE [#A] bash do case :IMPORTANT:
1816 | CLOSED: [2014-08-30 Sat 20:04]
1817 | http://www.thegeekstuff.com/2010/07/bash-case-statement/
1818 | #+begin_src sh
1819 | $ cat signal.sh
1820 | #!/bin/bash
1821 |
1822 | if [ $# -lt 2 ]
1823 | then
1824 | echo "Usage : $0 Signalnumber PID"
1825 | exit
1826 | fi
1827 |
1828 | case "$1" in
1829 |
1830 | 1) echo "Sending SIGHUP signal"
1831 | kill -SIGHUP $2
1832 | ;;
1833 | 2) echo "Sending SIGINT signal"
1834 | kill -SIGINT $2
1835 | ;;
1836 | 3) echo "Sending SIGQUIT signal"
1837 | kill -SIGQUIT $2
1838 | ;;
1839 | 9) echo "Sending SIGKILL signal"
1840 | kill -SIGKILL $2
1841 | ;;
1842 | *) echo "Signal number $1 is not processed"
1843 | ;;
1844 | esac
1845 | #+end_src
1846 | ** DONE shell if... then..: if true ; then echo "hello" ; fi
1847 | CLOSED: [2014-10-02 Thu 16:18]
1848 | ** DONE shell substract 2 variable: COUNT=`expr $FIRSTV - $SECONDV`
1849 | CLOSED: [2014-10-03 Fri 11:56]
1850 | ** DONE mac get file modified timestamp: stat -f "%Sm" -t "%s" $flagfile
1851 | CLOSED: [2014-10-03 Fri 11:41]
1852 | http://stackoverflow.com/questions/12169710/formatted-modified-date-time-on-mac-bash
1853 | ** DONE shell trim whitespace: echo "${output}" | sed -e 's/^[ \t]*//'
1854 | CLOSED: [2015-02-21 Sat 07:51]
1855 | ** DONE Bash run with parameter
1856 | CLOSED: [2015-03-19 Thu 11:42]
1857 | /usr/local/bin/run_command_in_all_nodes.sh "ssh $ssh_opt -t -t root@HOSTIP curl -L http://sprepo.fluigidentity.com/fluig_share/chef_cmd/deployment/$deploy_config_file | skip_monitor_log=1 repo_server_ip_port=$repo_server_ip_port deploy_version=$branch_name bash -e"
1858 |
1859 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
1860 | ** DONE track timespent
1861 | CLOSED: [2015-04-22 Wed 08:41]
1862 | START=$(date +%s)
1863 | backup_dir
1864 | END=$(date +%s)
1865 | DIFF=$(echo "$END - $START" | bc)
1866 | log "Track time spent: Backup step takes $DIFF seconds"
1867 | ** DONE bash -e and cron
1868 | CLOSED: [2015-04-26 Sun 18:42]
1869 | How to write a daily crontab script
1870 | #+BEGIN_EXAMPLE
1871 | root@ip-172-31-11-0:~/osc_it/backup_dir# vim /tmp/test.sh
1872 | root@ip-172-31-11-0:~/osc_it/backup_dir# chmod 755 /tmp/test.sh
1873 | root@ip-172-31-11-0:~/osc_it/backup_dir# bash /tmp/test.sh
1874 | /etc/hosts
1875 | ls: cannot access /etc/hosts2: No such file or directory
1876 | /etc/hosts
1877 | root@ip-172-31-11-0:~/osc_it/backup_dir# bash -e /tmp/test.sh
1878 | /etc/hosts
1879 | ls: cannot access /etc/hosts2: No such file or directory
1880 | root@ip-172-31-11-0:~/osc_it/backup_dir# cat /tmp/test.sh
1881 | #!/bin/bash -e
1882 | ls /etc/hosts
1883 | ls /etc/hosts2
1884 | ls /etc/hosts
1885 | #+END_EXAMPLE
1886 | ** DONE cat VS tac
1887 | CLOSED: [2015-04-27 Mon 18:53]
1888 | http://stackoverflow.com/questions/742466/how-can-i-reverse-the-order-of-lines-in-a-file
1889 | ** DONE less vs more
1890 | CLOSED: [2015-04-27 Mon 18:54]
1891 | ** DONE [#C] bash array separate by new line, instead of whitespace
1892 | CLOSED: [2015-07-09 Thu 07:57]
1893 | http://mindspill.net/computing/linux-notes/using-the-bash-ifs-variable-to-make-for-loops-split-with-non-whitespace-characters/
1894 | http://stackoverflow.com/questions/19771965/split-bash-string-by-newline-characters
1895 |
1896 | checks="check_gui_home -t 20
1897 | check_gui_login"
1898 |
1899 | IFS=$'\n'
1900 |
1901 | for a in $checks; do echo "--" "$a" "--" ; done
1902 | unset IFS
1903 | ** DONE bash divide numbers: echo 5/2 | bc -l: use bc or bash
1904 | CLOSED: [2015-07-21 Tue 16:46]
1905 | http://stackoverflow.com/questions/1088098/how-do-i-divide-in-the-linux-console
1906 |
1907 | string=84415266816
1908 | echo "$string/(1024*1024*1024)" | bc -l
1909 |
1910 | echo $(( 7 / 3 ))
1911 | ** DONE [#A] bash filter string: echo $ram_capacity | sed -n 's/.*\(free.*\)}/\1/p'
1912 | CLOSED: [2015-07-21 Tue 16:05]
1913 | http://stackoverflow.com/questions/11568859/how-to-extract-text-from-a-string-using-sed
1914 | MacPro:default mac$ echo $ram_capacity
1915 | {u'used': 5064916008, u'total': 84415266816, u'quotaTotal': 84415266816, u'usedByData': 39025953, u'free': 79350350808}
1916 |
1917 | ram_capacity="{u'used': 5064916008, u'total': 84415266816, u'quotaTotal': 84415266816, u'usedByData': 39025953, u'free': 79350350808}"
1918 | echo $ram_capacity | sed -n 's/.*\(free.*\)}/\1/p'
1919 | ** DONE [#A] bash function mute output :IMPORTANT:
1920 | CLOSED: [2015-08-01 Sat 22:06]
1921 | #+BEGIN_SRC sh
1922 | #!/bin/bash -e
1923 | function fun() {
1924 | INSTANCE_ID="id1"
1925 | echo "hello, world"
1926 | }
1927 |
1928 | echo "run0:"
1929 | fun
1930 |
1931 | val1=${fun}
1932 | echo "run1: $val1"
1933 |
1934 | val2=$(fun)
1935 | echo "run2: $val2"
1936 |
1937 | echo "INSTANCE_ID: $INSTANCE_ID".
1938 | #+END_SRC
1939 |
1940 | #+BEGIN_EXAMPLE
1941 | MacPro:~ mac$ ./test.sh
1942 | run0:
1943 | hello, world
1944 | run1:
1945 | run2: hello, world
1946 | INSTANCE_ID: id1.
1947 | #+END_EXAMPLE
1948 | ** DONE linux convert string to int
1949 | CLOSED: [2015-08-02 Sun 08:20]
1950 | http://stackoverflow.com/questions/11268437/how-to-convert-string-to-integer-in-unix
1951 |
1952 | expr $d1 - $d2
1953 | You can also do:
1954 |
1955 | echo $(( d1 - d2 ))
1956 |
1957 | [ `expr "22" - 23 ` -gt 0 ]; echo $?
1958 | ** # --8<-------------------------- separator ------------------------>8--
1959 | ** DONE bash: from a list of directories, remove all except the first two: ls -lth /tmp/ | awk 'NR>2'
1960 | CLOSED: [2015-08-13 Thu 08:16]
1961 | #+BEGIN_EXAMPLE
1962 | jenkins@1e7c2d4de548:/var/www/repo$ ls -lth | grep dev_code | awk -F' ' '{print $9}'
1963 | dev_code_9d820f6df69cccc2b28be12336a0e4bf88c4d555
1964 | dev
1965 | dev_code_b13a247cf739d75368d63180e5218d22c0c73fdd
1966 | dev_code_4610882ea3b665908ba0726f186ce730ab8a0e9f
1967 | dev_code_ba1965c75f3ccd28f0f37bff0916ed48154c90ed
1968 | dev_code_71d197967f92bb0600afe2d307d1dd86315d5835
1969 | dev_code_0e45206e90a6c1603db676a085b6c531ed655e62
1970 | dev_code_0d23ccf8544ccb87e4511a3c65c8358c15d5325b
1971 | dev_code_429b951934969a7055b72ec2aa9a5549b7778981
1972 | #+END_EXAMPLE
1973 | ** DONE bash print line #2 and line #3: ls -lth /tmp/ | awk 'NR==2,NR==3'
1974 | CLOSED: [2015-08-13 Thu 08:16]
1975 | #+BEGIN_EXAMPLE
1976 | MacPro:org_data mac$ ls -lth /tmp/ | awk 'NR==2,NR==3'
1977 | drwx------ 3 root wheel 102B Aug 13 06:05 KSOutOfProcessFetcher.0.I5ci1K_TwCwqo1sKvc0siaBbJTw=
1978 | -rw-r--r-- 1 mac wheel 8.4K Aug 13 01:41 pre_push.log
1979 | MacPro:org_data mac$ ls -lth /tmp/
1980 | total 32
1981 | drwx------ 3 root wheel 102B Aug 13 06:05 KSOutOfProcessFetcher.0.I5ci1K_TwCwqo1sKvc0siaBbJTw=
1982 | -rw-r--r-- 1 mac wheel 8.4K Aug 13 01:41 pre_push.log
1983 | -rw-r--r-- 1 mac wheel 1.5K Aug 9 09:49 test_docker_reboot.sh
1984 | drwx------ 3 root wheel 102B Aug 7 19:07 launchd-412.p65VLV
1985 | drwx------ 3 mac wheel 102B Aug 7 19:07 launch-fHcqj0
1986 | drwx------ 3 mac wheel 102B Aug 7 19:07 launch-v7pPEn
1987 | drwx------ 3 mac wheel 102B Aug 7 19:05 launchd-268.WPmyrE
1988 | drwx------ 3 _spotlight wheel 102B Aug 7 19:03 launchd-261.pK6Cby
1989 | MacPro:org_data mac$
1990 | #+END_EXAMPLE
1991 | ** DONE copy a list of files preseving the directory path
1992 | CLOSED: [2015-08-13 Thu 08:25]
1993 | http://serverfault.com/questions/180853/how-to-copy-file-preserving-directory-path-in-linux
1994 | #+BEGIN_EXAMPLE
1995 | rm -rf /tmp/backup/*
1996 | cp -r --parents /var/lib/jenkins/jobs/BuildRepoCode /tmp/backup
1997 | ls -lth /tmp/backup
1998 | #+END_EXAMPLE
1999 | ** DONE bash string to list delimiter separator: IFS=$'\n'; echo "${System[*]}"
2000 | CLOSED: [2015-10-27 Tue 11:01]
2001 | http://superuser.com/questions/461981/how-do-i-convert-a-bash-array-variable-to-a-string-delimited-with-newlines
2002 |
2003 | #+BEGIN_EXAMPLE
2004 | Here's a way that utilizes bash parameter expansion and its IFS special variable.
2005 |
2006 | $ System=('s1' 's2' 's3' 's4 4 4')
2007 | $ ( IFS=$'\n'; echo "${System[*]}" )
2008 | #+END_EXAMPLE
2009 | ** DONE base dirname: echo ${PIDFILE%/*}
2010 | CLOSED: [2015-11-24 Tue 20:33]
2011 | #+BEGIN_EXAMPLE
2012 | Denny-mac:~ mac$ PIDFILE="/etc/hosts/abc/123/tmp.pid"
2013 | You have new mail in /var/mail/mac
2014 | Denny-mac:~ mac$ echo ${PIDFILE%/*}
2015 | /etc/hosts/abc/123
2016 | #+END_EXAMPLE
2017 | ** DONE bash check variable is number
2018 | CLOSED: [2016-05-02 Mon 18:41]
2019 | http://stackoverflow.com/questions/806906/how-do-i-test-if-a-variable-is-a-number-in-bash
2020 |
2021 | #+BEGIN_SRC sh
2022 | re='^[0-9]+$'
2023 | if ! [[ $yournumber =~ $re ]] ; then
2024 | echo "error: Not a number" >&2; exit 1
2025 | fi
2026 | #+END_SRC
2027 | ** DONE bash count matched string: echo "echo 1234 echo" | grep -o echo
2028 | CLOSED: [2016-05-23 Mon 07:47]
2029 | http://stackoverflow.com/questions/6741967/how-can-i-count-the-occurrences-of-a-string-within-a-file-using-bash
2030 | ** DONE bash check whethter string is a valid ip
2031 | CLOSED: [2016-05-30 Mon 17:44]
2032 | http://stackoverflow.com/questions/13777387/check-for-ip-validity
2033 | #+BEGIN_SRC sh
2034 | #!/bin/bash
2035 | ip=1.2.3.4
2036 |
2037 | if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
2038 | echo "success"
2039 | else
2040 | echo "fail"
2041 | fi
2042 | #+END_SRC
2043 | ** DONE Changing a linux password via script: echo "root:NEWPASSWD" | chpasswd :noexport:
2044 | CLOSED: [2016-06-01 Wed 13:59]
2045 | http://stackoverflow.com/questions/27837674/changing-a-linux-password-via-script
2046 |
2047 | echo "root:DevOpsChangeMe1" | chpasswd
2048 |
2049 | ssh -i my_id_rsa root@104.131.129.100 "echo root:NEWPASSWD | chpasswd"
2050 |
2051 | echo -e "newpasswd123\nnnewpasswd123" | passwd user
2052 | ** DONE bash to check whether ssh server reachable
2053 | CLOSED: [2016-06-10 Fri 10:57]
2054 | function ip_list_ping_reachable() {
2055 | # Sample:
2056 | # ip_list_ping_reachable "true" "172.17.0.2
2057 | # 172.17.0.3
2058 | # 172.17.0.4"
2059 | # ip_list_ping_reachable "false" "$ip_list"
2060 | local exit_if_fail=${1?}
2061 | local ip_list=${2?}
2062 | for ip in $ip_list; do
2063 | # echo "ping ip: ${ip}"
2064 | if ! ping -c3 "$ip" 2>/dev/null 1>/dev/null; then
2065 | if [ "$exit_if_fail" = "true" ]; then
2066 | echo "ERROR: Current machine can't ping $ip. Please check input parameters."
2067 | exit 1
2068 | else
2069 | echo "Warning: Current machine can't ping $ip. Please check input parameters."
2070 | fi
2071 | fi
2072 | done
2073 | }
2074 | ** DONE bash get file acl mode: stat -c "%a %n" /etc/hosts
2075 | CLOSED: [2016-06-14 Tue 16:29]
2076 | http://askubuntu.com/questions/152001/how-can-i-get-octal-file-permissions-from-command-line
2077 | ** DONE bash break long line to short line
2078 | CLOSED: [2016-06-17 Fri 10:59]
2079 | http://unix.stackexchange.com/questions/82182/having-multi-lines-in-bash-command-substitution
2080 | http://stackoverflow.com/questions/18599711/how-can-i-split-a-bash-command-over-multiple-lines-when-using-an-if-statement
2081 | #+BEGIN_SRC sh
2082 | package_list="lsof curl git tar apt wget vim strace \
2083 | libcurl3 openssh-client "
2084 | #+END_SRC
2085 | ** DONE shell break for and continue
2086 | CLOSED: [2015-05-13 Wed 22:19]
2087 | http://www.tutorialspoint.com/unix/unix-loop-control.htm
2088 | - break
2089 | #+BEGIN_SRC sh
2090 | #!/bin/sh
2091 |
2092 | for var1 in 1 2 3
2093 | do
2094 | for var2 in 0 5
2095 | do
2096 | if [ $var1 -eq 2 -a $var2 -eq 0 ]
2097 | then
2098 | break 2
2099 | else
2100 | echo "$var1 $var2"
2101 | fi
2102 | done
2103 | done
2104 | #+END_SRC
2105 |
2106 | - continue
2107 | #+BEGIN_SRC sh
2108 | #!/bin/sh
2109 |
2110 | NUMS="1 2 3 4 5 6 7"
2111 |
2112 | for NUM in $NUMS
2113 | do
2114 | Q=`expr $NUM % 2`
2115 | if [ $Q -eq 0 ]
2116 | then
2117 | echo "Number is an even number!!"
2118 | continue
2119 | fi
2120 | echo "Found odd number"
2121 | done
2122 | #+END_SRC
2123 | ** DONE Check if a function exists before executing it in shell
2124 | CLOSED: [2016-01-29 Fri 17:27]
2125 | http://stackoverflow.com/questions/17972087/check-if-a-function-exists-before-executing-it-in-shell
2126 | http://www.cyberciti.biz/faq/bash-shell-scripting-find-out-if-function-definedornot/
2127 | #+BEGIN_SRC sh
2128 | if type foo | grep -i function > /dev/null; then
2129 | # foo is a function
2130 | fi
2131 | #+END_SRC
2132 | ** TODO set -o pipefail
2133 | pipefail: the return value of a pipeline is the status of the last
2134 | command to exit with a non-zero status, or zero if no command exited
2135 | with a non-zero status
2136 |
2137 | http://stackoverflow.com/questions/1221833/bash-pipe-output-and-capture-exit-status
2138 | ** DONE bash remove whitespace and new line
2139 | CLOSED: [2016-12-08 Thu 17:44]
2140 | http://stackoverflow.com/questions/13659318/how-to-remove-space-from-string
2141 |
2142 | http://www.regular-expressions.info/posixbrackets.html
2143 |
2144 | jenkins_jobs="BuildMDMRepo ,UpdateSandboxMDM,UpdateJenkinsItself,TailLogfile,CollectFiles"
2145 | echo "${jenkins_jobs//[[:blank:]]/}"
2146 |
2147 | echo "$jenkins_jobs" | tr -s " "
2148 |
2149 | #!/bin/bash -e
2150 | jenkins_jobs="BuildMDMRepo ,
2151 | UpdateSandboxMDM,UpdateJenkinsItself,TailLogfile,CollectFiles"
2152 | echo "${jenkins_jobs//[[:space:]]/}"
2153 | ** # --8<-------------------------- separator ------------------------>8--
2154 | ** DONE remove old backup and keep laest 2 backup
2155 | CLOSED: [2016-12-26 Mon 10:45]
2156 | ssh -p 2702 root@138.68.4.184
2157 |
2158 | > /tmp/test.sh && vim /tmp/test.sh
2159 |
2160 | bash /tmp/test.sh
2161 |
2162 | #+BEGIN_SRC sh
2163 | #!/bin/bash
2164 | function remove_old_folder() {
2165 | folder_to_check=${1?}
2166 | keep_latest_count=${2:-1}
2167 | i=1
2168 | cd "$folder_to_check"
2169 | for d in $(ls -t .); do
2170 | echo "d: $d, i: $i, keep_latest_count: $keep_latest_count"
2171 | if [ $i -gt $keep_latest_count ]; then
2172 | echo "rm $folder_to_check/$d"
2173 | #rm -rf "$folder_to_check/$d"
2174 | fi
2175 | i=$((i+1))
2176 | done
2177 | }
2178 |
2179 | remove_old_folder "/mnt/cb-backup-01/backup/mdm-staging/" 1
2180 | #+END_SRC
2181 | *** output
2182 | #+BEGIN_EXAMPLE
2183 | root@prod-cb-backup:/mnt/cb-backup-01/backup/mdm-staging# dir_to_check="/mnt/cb-backup-01/backup/mdm-staging/"
2184 | root@prod-cb-backup:/mnt/cb-backup-01/backup/mdm-staging# for d in $(find "$dir_to_check" -type d -ctime +7); do
2185 | > if [ -d "$d" ]; then
2186 | > echo "rm $d"
2187 | > rm -rf $d
2188 | > fi
2189 | > done
2190 | root@prod-cb-backup:/mnt/cb-backup-01/backup/mdm-staging# ls -lth
2191 | total 12K
2192 | drwxr-xr-x 3 root root 4.0K Dec 25 01:47 2016-12-25T064711Z
2193 | root@prod-cb-backup:/mnt/cb-backup-01/backup/mdm-staging# date
2194 | Sun Dec 25 05:52:57 EST 2016
2195 |
2196 | find . -maxdepth 1 -type d -ctime +7
2197 |
2198 | root@prod-cb-backup:/mnt/cb-backup-01/backup/mdm-staging# find . -maxdepth 1 -type d -ctime +7
2199 | root@prod-cb-backup:/mnt/cb-backup-01/backup/mdm-staging# ls
2200 | 2016-12-11T053231Z 2016-12-18T060028Z 2016-12-25T064711Z
2201 | root@prod-cb-backup:/mnt/cb-backup-01/backup/mdm-staging# stat 2016-12-11T053231Z
2202 | Size: 4096 Blocks: 8 IO Block: 4096 directory
2203 | Device: 810h/2064d Inode: 16252977 Links: 7
2204 | Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
2205 | Access: 2016-12-25 04:57:02.775279051 -0500
2206 | Modify: 2016-12-24 00:22:22.999279051 -0500
2207 | Change: 2016-12-24 00:22:22.999279051 -0500
2208 | Birth: -
2209 | #+END_EXAMPLE
2210 | ** DONE shell get current file name: basename "$0"
2211 | CLOSED: [2017-05-12 Fri 22:53]
2212 | ** DONE Turning multiple lines into one line with comma separated: sed -e 's/ /,/g'
2213 | CLOSED: [2017-09-08 Fri 17:34]
2214 | https://stackoverflow.com/questions/15758814/turning-multiple-lines-into-one-line-with-comma-separated-perl-sed-awk
2215 | ** DONE bash number calculation
2216 | CLOSED: [2017-10-17 Tue 22:17]
2217 | #+BEGIN_EXAMPLE
2218 | #!/usr/bin/env bash
2219 | ##-------------------------------------------------------------------
2220 | ## @copyright 2017 DennyZhang.com
2221 | ## Licensed under MIT
2222 | ## https://www.dennyzhang.com/wp-content/mit_license.txt
2223 | ##
2224 | ## File: test.sh
2225 | ## Author : Denny
2226 | ## Description :
2227 | ## https://leetcode.com/problems/cheatsheet-shell-A4/description/][leetcode.com]]
2228 | ## --
2229 | ## Created : <2017-10-17>
2230 | ## Updated: Time-stamp: <2017-10-17 22:13:31>
2231 | ##-------------------------------------------------------------------
2232 | set -e
2233 |
2234 | one_line=($(head -n1 ./file.txt))
2235 | column_count=${#one_line[@]}
2236 | line_count=$(wc -l ./file.txt | awk -F' ' '{print $1}')
2237 |
2238 | # echo "column_count: $column_count, line_count: $line_count"
2239 | output=($(cat ./file.txt))
2240 | # echo "output: $output"
2241 |
2242 | for((i=0; i<$column_count; i++)); do
2243 | for((j=0; j<$line_count; j++)); do
2244 | index=$((i+j*column_count))
2245 | if [ $((j+1)) -eq $line_count ]; then
2246 | echo -n "${output[$index]}"
2247 | else
2248 | echo -n "${output[$index]} "
2249 | fi
2250 | # echo "${output[$index} "
2251 | done
2252 | echo ""
2253 | done
2254 | #+END_EXAMPLE
2255 | ** DONE shell replace string: get master-index-023ea45 from master-index-023ea45: echo "${var//-index/}"
2256 | CLOSED: [2018-01-29 Mon 16:27]
2257 | * Useful shell code snippet :noexport:Coding:
2258 | :PROPERTIES:
2259 | :type: Language_Linux
2260 | :END:
2261 |
2262 | #+begin_example
2263 | Please note: WORDPRESS differentiates among the following:
2264 | | |, ' ', -- -, ""
2265 | #+end_example
2266 |
2267 | - process
2268 | | Question | Solution | Use case |
2269 | |-----------------------------------+--------------------------------------------------------------------------------------------------------------------+-----------------------------------|
2270 | | 列出某个进程打开了哪些文件 | lsof +p 1971 | |
2271 | | 显示内存占用量最高的前10个process | ps aux | sort -nk +4 | tail | |
2272 | | 查看某类进程启动的时间 | ps -ef | awk '/[p]hp-fpm/{print $2,$5,$7,$8}' | 查找超时进程 |
2273 | | 列出运行超过一天的php进程 | ps -o etime,ppid,uid,pid,command -e | grep '/usr/bin/php' | awk -F' ' '{print $1" "$2" "$5}' | grep '^[0-9]\+-' | 查找超时进程 |
2274 | | 列出所有父进程为init1的进程 | ps -f --ppid 1 | 查找孤儿进程,判断是否进行垃圾回收 |
2275 | | 如何查出某个pid运行在哪个cpu上 | ps -efP | grep 21587 | |
2276 | | get process detail start time | ps -o uid,pid,etime -p 11880 | |
2277 | | 查看emacs的资源占用情况 | top -p $(pidof emacs) | |
2278 |
2279 | - Common used
2280 | | Question | Solution | Use case |
2281 | |--------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------|
2282 | | 按更新时间, 查看某个文件夹 | ls -alth | |
2283 | | 循环运行某个命令 | for ((b=1; b<=100; b++)); do echo hello; done; | |
2284 | | if...else的条件判断 | if [ ! -d /tmp/tt ]; then mkdir /tmp/tt; else echo exists; fi; | |
2285 | | 模拟并发请求 | 在多个terminal下,同时执行: for ((b=1; b<=100; b++)); do thrift_client -c sanityCheck -s 192.168.75.108 -p 9401; done; | |
2286 | | 对一组远端服务器, 同时执行某个命令 | command="date"; for puppet_client_ip in "192.168.75.108" "192.168.75.109" "192.168.75.110" "192.168.75.111"; do ssh -o StrictHostKeyChecking=no root@$puppet_client_ip "$command";done; | |
2287 | | 向文件中追加一个key=value的键值对, 如果存在则修改它 | (grep "key1 \+=" ./test.cfg && sudo sed -i 's/key1 \+=.*/key1 = value1/' ./test.cfg) || ((cat ./test.cfg; echo "key1 = value1") | sudo tee ./test.cfg) | |
2288 | | 查看svn的某个revision的修改 | svn diff -r 135:136 http://test.server.cn/project/trunk | |
2289 | | 临时进入某个目录, 并运行某个命令, 同时不改变当前目录的位置 | (cd /tmp && ls) | |
2290 | | 当命令A执行完后, 需要执行命令B, 但不修改$? | A && B || true | |
2291 | | 查看某个文件夹下, 今天被修改文件的最后若干行 | | |
2292 | | 在指定时间运行某个命令 | echo "ls -l" | at midnight | |
2293 | | 重新执行上一个命令 | (sudo !!) | |
2294 | | 按字符串搜索查找某个文件夹 | grep -lir "some text" * | |
2295 | | 监控某个文件是否被修改了 | yum install inotify-tools; while inotifywait -e modify /var/log/message; do echo "changed"; done | |
2296 |
2297 | - file management
2298 | | Question | Solution | Use case |
2299 | |-------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------|
2300 | | 查看某个文件的第5到第8行 | sed -n 5,8p /etc/hosts | |
2301 | | 删除某个文件指定的几行 | sed -i 2,3d /etc/hosts | |
2302 | | 列出某个文件中太长的行 | awk 'length>50' /etc/hosts | |
2303 | | 列出某个文件夹下, 最近60分钟内被修改的文件及文件夹 | sudo find /var/log -mmin 60 -type f | |
2304 | | 列出/var/log/下, 文件大小介于50k到100k之间的文件 | sudo find /var/log -type f -size +50k -size -100k | |
2305 | | 找出满足条件的文件, 并将它们删除 | find ./ -name Thumbs.db -delete | |
2306 | | Graphical tree of sub-directories | ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/' | |
2307 | | quickly backup or copy a file with bash | cp filename{,.bak} | |
2308 | | Delete all files in a folder that don't match a certain file extension | rm !(*.foo|*.bar|*.baz) | |
2309 | | List the size (in human readable form) of all sub folders from the current location | du -h --max-depth=1 | |
2310 | | make directory tree | mkdir -p work/{d1,d2}/{src,bin,bak} | |
2311 | | 递归地删除所有空文件夹 | find . -type d -empty -delete | |
2312 | | 比较两个目录树的差异 | diff <(cd dir1 && find | sort) <(cd dir2 && find | sort) | |
2313 | | Get the 10 biggest files/folders for the current direcotry | du -s * | sort -n | tail | |
2314 | | Remove all but one specific file | rm -f !(survivior.txt) | |
2315 | | Find files that were modified by a given command | touch /tmp/file ; $EXECUTECOMMAND ; find /path -newer /tmp/file | |
2316 | | Copy a file structure without files | find * -type d -exec mkdir /where/you/wantem/\{\} \; | |
2317 | | 找出一个文件夹下, md5相同的文件 | fdupes -r . 或者 find . -type f -exec md5sum '{}' ';' | sort | uniq --all-repeated=separate -w 33 | cut -c 35- | |
2318 | | 对于一个文件, 指定两个开始和结束的regexp, 只显示满足条件的区间内容 | awk '/127.0.0.1/,/The following/' /etc/hosts | |
2319 | | 删除修改时间在一年以上的文件 | find -mtime +365 -and -not -type d -delete | 删除不需要的文件 |
2320 | | 创建一个指定大小的文件 | truncate -s 1M file 或者 dd if=/dev/zero of=foo.txt bs=1M count=1 | 测试文件系统性能 |
2321 | | 找出最新三天修改的某类文件 | find . -name "*.org" -a \( -mtime 0 -o -mtime 1 -o -mtime 2 \) | |
2322 | | 创建文件时, 指定acl | umask 226 && echo "stack ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/50_stack_sh | |
2323 | | 打印一个文件夹的所有内容 | for f in `ls .` ; do { echo -e "\n======== $f ======"; tail $f;}; done | |
2324 |
2325 | - network
2326 | | Question | Solution | Use case |
2327 | |------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------|
2328 | | 查看某个tcp端口被哪个pid占用 | lsof -i tcp:80 | |
2329 | | 显示本机与所有remote host已经建立的网络链接 | netstat -an | grep ESTABLISHED | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | awk '{ printf("%s\t%s\t",$2,$1) ; for (i = 0; i < $1; i++) {printf("*")}; print "" }' | |
2330 | | 显示本机的外网ip | curl ifconfig.me | |
2331 | | Show apps that use internet connection at the moment | ss -p | |
2332 | | List alive hosts in specific subnet | nmap -sP 192.168.1.0/24 | |
2333 | | 查看当前网段, 有哪些机器开了某个端口 | nmap -sT -p 80 -oG - 192.168.1.* | |
2334 | | check open ports | lsof -Pni4 | grep LISTEN | |
2335 | | 查看各网卡的流入与流出带宽 | ifstat -nt | |
2336 | | 诊断网络状况 | mtr --report-cycles=5 --interval=2 --split | |
2337 |
2338 | - remote host management
2339 | | Question | Solution | Use case |
2340 | |----------------------------------+----------------------------------------------------------------------------------+----------|
2341 | | 对两个不同机器上的文件进行diff | diff <(ssh alice cat /etc/apt/sources.list) <(ssh bob cat /etc/apt/sources.list) | |
2342 | | 在远端的两个host之间进行文件传输 | scp user@hostb:file user@hostc: | |
2343 |
2344 | - view system information
2345 | | Question | Solution | Use case |
2346 | |--------------------------------------------+-----------------------------------------------------------+----------|
2347 | | 将当前机器硬件生成一个全面,美观的html报表 | lshw -html > hardware.html | |
2348 | | 查看OS是64位, 还是32位 | file /usr/bin/file; uname -m; getconf -a | grep LONG_BIT | |
2349 | | 查看CPU信息 | cat /proc/cpuinfo | |
2350 | | 如何查看linux系统是哪个版本的 | lsb_release -a | |
2351 | | 查看系统内核 | uname -a | |
2352 |
2353 | - Memory
2354 | | Question | Solution | Use case |
2355 | |--------------------------+-------------------------------------+----------|
2356 | | 按内存使用量对进程排序 | ps -eo pid,pmem,rss,comm --sort rss | |
2357 | | 查看某个进程的内存使用量 | ps -p 2977 -o vsz= | |
2358 | | 查看某个进程的内存使用量 | pmap 2977 | |
2359 | | 查看某个进程的内存使用量 | top -n 1 -p 2977 | |
2360 | | 显示系统内存使用情况 | free -m -t | |
2361 | | 显示系统内存使用情况 | cat /proc/meminfo | |
2362 |
2363 | - Misc
2364 | | Question | Solution | Use case |
2365 | |-------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+----------|
2366 | | 在指定时间点运行某个脚本 | at -f /tmp/test.sh -v 18:07 | |
2367 | | Convert seconds to human-readable format | date -d@1234567890 | |
2368 | | Get utc seconds | date +%s | |
2369 | | get yesterday | date "+%a %d/%m/%Y" --date="1 days ago" | |
2370 | | Quick access to the ascii table. | man ascii | |
2371 | | Start COMMAND, and kill it if still running after 5 seconds | timeout 5s COMMAND | |
2372 | | 产生一串随机数 | echo $RANDOM; echo {0..1}{0..1}{0..1}{0..1} | |
2373 | | 限制某个进程对cpu的使用率 | cpulimit -p 1234 -l 50 | |
2374 | | 列出当前安装软件的包大小 | dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -n | |
2375 | | 按固定大小将一个大文件切分成几个小文件 | split -b 500k /var/log/messages message_part_ | |
2376 | | Display GCC Predefined Macros | gcc -dM -E - < /dev/null | |
2377 | | svn up某个文件夹下的所有子文件夹 | find . -maxdepth 1 -type d | xargs svn up | |
2378 | | 批量缩小图片 | rm -rf ../new && mkdir ../new && for img in `find . -iname '*.jpg' -a -size +1M`; do convert -resize 50%x50% "$img" ../new/"$img"; done | |
2379 | | 计算sin(5)的值 | echo 's(5)' | bc -l | |
2380 | | 找出满足条件的文件夹,进行删除 | ls -t /var/lib/hudson/jobs | xargs -I '{}' find /var/lib/hudson/jobs/'{}'/builds/ -name "*" -mtime +15 -and -not -type d -delete | |
2381 | | 算md5值 | echo -n "password" | md5sum | |
2382 | | 列出所有本机IPv4的网络连接 | lsof -Pnl +M -i4 | |
2383 | | CPU architecture information helper | cat /proc/cpuinfo; lscpu | |
2384 | | 下载递归某个站点 | wget -r -p -np -k http://xxx.com/abc/ | |
2385 | | 直接在控制台可以运行的, shell for循环 | for((i=0; i< 3; i++)); do { echo $i; }; done | |
2386 | | 将patch.cfg中的1.3.x字符串替换成1.3.x, 1.4.x | sed -i 's/1.3.x/1.3.x, 1.4.x/g' patch.cfg | |
2387 | | 将十进制转成十六进制 | bc <<< "obase=16; 11" | |
2388 | | 查看机器是否为虚拟机 | dmidecode -s system-manufacturer | |
2389 | | hexdump以二进制看文件 | hexdump -C -n 100 caifv-images.s3.b2c.ekaidian.com.elmar0516 | |
2390 | | 查看某个文件第10字节后的20个字节 | hexdump -C -n 20 -s 10 /etc/hosts | |
2391 | | grep只显示matched的string | grep --only-matching '[^ ]*fxw.vmod.cn' /usr/local/nginx/conf/vhosts/default.conf | |
2392 | ** DONE linux at命令: 定义一个定时任务,在指定时间内执行 :noexport:
2393 | CLOSED: [2012-05-28 Mon 18:09]
2394 | #+begin_example
2395 | ///6f667c06190b783231f9e708249a1d5d#$cat /tmp/test.sh
2396 | echo `date` >>/tmp/test.log
2397 | ///6f667c06190b783231f9e708249a1d5d#$/etc/init.d/atd status
2398 | atd (pid 4060) is running...
2399 | ///6f667c06190b783231f9e708249a1d5d#$date
2400 | Mon May 28 18:05:30 CST 2012
2401 | ///6f667c06190b783231f9e708249a1d5d#$sudo at -f /tmp/test.sh -v 18:06
2402 | Mon May 28 18:06:00 2012
2403 |
2404 | job 1 at 2012-05-28 18:06
2405 | ///6f667c06190b783231f9e708249a1d5d#$sudo at -f /tmp/test.sh -v 18:07
2406 | Mon May 28 18:07:00 2012
2407 |
2408 | job 2 at 2012-05-28 18:07
2409 | ///6f667c06190b783231f9e708249a1d5d#$date
2410 | Mon May 28 18:07:01 CST 2012
2411 | ///6f667c06190b783231f9e708249a1d5d#$cat /tmp/test.log
2412 | Mon May 28 18:06:00 CST 2012
2413 | Mon May 28 18:07:00 CST 2012
2414 | #+end_example
2415 | ** DONE 运行某个shell命令, 但如果$?是失败的,仍然返回失败: 通过中间变量来实现
2416 | CLOSED: [2012-09-10 一 00:50]
2417 | echo http://192.168.75.236:8999/health_check/report.html && ssh root@192.168.75.108 "ecae-health-check --report-dir /usr/local/ecae-health-check/report --only-simpletest"; scp root@192.168.75.108://usr/local/ecae-health-check/report/report.html /var/lib/hudson/tsung_log/health_check/report.html
2418 | ** sample usage :noexport:
2419 | #+begin_src python
2420 | #!/usr/bin/python
2421 | # __CR__
2422 | # Copyright (c) 2008-2010 EMC Corporation
2423 | # All Rights Reserved
2424 | #
2425 | # This software contains the intellectual property of EMC Corporation
2426 | # or is licensed to EMC Corporation from third parties. Use of this
2427 | # software and the intellectual property contained therein is expressly
2428 | # limited to the terms and conditions of the License Agreement under which
2429 | # it is provided by or on behalf of EMC.
2430 | # __CR__
2431 |
2432 | #
2433 |
2434 | #
2435 | # author: Denny Zhang
2436 | # date: 06/07/10
2437 | #
2438 |
2439 | import sys
2440 | import os
2441 | import getopt
2442 | import xml.dom.minidom
2443 |
2444 | ELEMENT_NAME = "entry"
2445 | ATTRIBUTE_KEY = "key"
2446 | ATTRIBUTE_VALUE = "value"
2447 |
2448 | #default indentation when adding new entry
2449 | INDENTATION = "\n "
2450 |
2451 | FAILURE = 1
2452 | SUCCESS = 0
2453 |
2454 | """
2455 | Update xml configuration files, for the given key.
2456 | """
2457 |
2458 | class AtmosXMLCfg:
2459 | """
2460 | AtmosXMLCfg manage maui xml configuration.
2461 | Notice: The format of each entry shall be "
2462 | """
2463 |
2464 | ####################### Public Begin #######################################
2465 | def update_entry(self, key_name, key_value):
2466 | """
2467 | Find first entry of , update the value with key_value.
2468 |
2469 | Raise exception for unexpected content of xml.
2470 | """
2471 | count = self.__count_element_by_attribute(ELEMENT_NAME, ATTRIBUTE_KEY, key_name)
2472 | if count != 1:
2473 | msg = "Find %d entries, rather than exactly 1, with the value of <%s %s=\"%s\" ...>!" % \
2474 | (count, ELEMENT_NAME, ATTRIBUTE_KEY, key_name)
2475 | raise Exception(msg)
2476 |
2477 | element = self.__get_first_element_by_attribute(ELEMENT_NAME, ATTRIBUTE_KEY, key_name)
2478 |
2479 | if element.hasAttribute(ATTRIBUTE_VALUE) == False:
2480 | msg = "Can't find entry <%s %s=\"\" %s=\"\">!" % \
2481 | (ELEMENT_NAME, ATTRIBUTE_KEY, ATTRIBUTE_VALUE)
2482 | raise Exception(msg)
2483 |
2484 | element.setAttribute(ATTRIBUTE_VALUE, key_value)
2485 |
2486 | def remove_entry(self, key_name):
2487 | """
2488 | Remove entry with the attribute of key_name.
2489 |
2490 | Raise exception for unexpected content of xml.
2491 | """
2492 | count = self.__count_element_by_attribute(ELEMENT_NAME, ATTRIBUTE_KEY, key_name)
2493 | # The qualified element shall be exactly one.
2494 | if count != 1:
2495 | msg = "Find %d entries, rather than exactly 1, with the value of <%s %s=\"%s\" ...>!" % \
2496 | (count, ELEMENT_NAME, ATTRIBUTE_KEY, key_name)
2497 | raise Exception(msg)
2498 |
2499 | element = self.__get_first_element_by_attribute(ELEMENT_NAME, ATTRIBUTE_KEY, key_name)
2500 |
2501 | parent_element = element.parentNode
2502 | parent_element.removeChild(element)
2503 |
2504 | def add_entry(self, last_key_name, key_name, key_value, indentation):
2505 | """
2506 | Add an entry after the first entry which is
2507 |
2508 | If we fail to find the entry to append the new entry, append the entry as the last child.
2509 |
2510 | Raise exception for unexpected content of xml.
2511 | """
2512 | count = self.__count_element_by_attribute(ELEMENT_NAME, ATTRIBUTE_KEY, key_name)
2513 | # When adding new entry, it shall not exists before
2514 | if count != 0:
2515 | msg = "Already have %d entries, with the value of <%s %s=\"%s\" ...>!" % \
2516 | (count, ELEMENT_NAME, ATTRIBUTE_KEY, key_name)
2517 | raise Exception(msg)
2518 |
2519 | if last_key_name == "":
2520 | parent_element = self.get_last_entry()
2521 | ref_child = None
2522 | else:
2523 | element = self.__get_first_element_by_attribute(ELEMENT_NAME, ATTRIBUTE_KEY, last_key_name)
2524 | if element == None:
2525 | msg = "Add entry fail: %s not found, can't add new entry." % (last_key_name)
2526 | raise Exception(msg)
2527 | # Get parent entry
2528 | parent_element = element.parentNode
2529 | ref_child = element.nextSibling
2530 |
2531 | # Construct a new entry
2532 | new_entry = self.xml_doc.createElement(ELEMENT_NAME)
2533 | key_attribute_node = self.xml_doc.createAttribute(ATTRIBUTE_KEY)
2534 | value_attribute_node = self.xml_doc.createAttribute(ATTRIBUTE_VALUE)
2535 |
2536 | new_entry.setAttributeNode(key_attribute_node)
2537 | new_entry.setAttribute(ATTRIBUTE_KEY, key_name)
2538 |
2539 | new_entry.setAttributeNode(value_attribute_node)
2540 | new_entry.setAttribute(ATTRIBUTE_VALUE, key_value)
2541 |
2542 | # insert the new entry to the right location
2543 | if ref_child == None:
2544 | parent_element.appendChild(new_entry)
2545 | else:
2546 | parent_element.insertBefore(new_entry, ref_child)
2547 |
2548 | # append a newline and prefix of indentation to the head of the new entry
2549 | empty_text_node = self.xml_doc.createTextNode(indentation)
2550 | parent_element.insertBefore(empty_text_node, new_entry)
2551 |
2552 | def write_xml_to_file(self, fname):
2553 | """
2554 | Flush xml dom object to a file.
2555 | """
2556 | fw = open(fname, 'w')
2557 | fw.write(self.xml_doc.toxml())
2558 | fw.close()
2559 |
2560 | def get_last_entry(self):
2561 | last_entry = None
2562 | if self.xml_doc.childNodes != None:
2563 | length = len(self.xml_doc.childNodes)
2564 | last_entry = self.xml_doc.childNodes[length -1 ]
2565 | return last_entry
2566 |
2567 | def xml_check(self):
2568 | """
2569 | Check whether the xml is in the right format.
2570 | Raise exception, if not.
2571 | The xml shall conform the following format:
2572 | - The xml is composed of three nodes: xml version, license, and maui properties.
2573 | - Each child node of maui properties shall be either comment,
2574 | text node or element node with the format of
2575 | - Maui properties's children shall have no duplicate key.
2576 | """
2577 | # TODO, denny
2578 | return
2579 |
2580 | ####################### Public End #######################################
2581 |
2582 | ####################### Private Begin ######################################
2583 | def __init__(self, fname):
2584 | self.fname = fname
2585 | self.xml_doc = xml.dom.minidom.parse(self.fname)
2586 | self.xml_check()
2587 |
2588 | def __count_element_by_attribute(self, tag_name, attribute_name, \
2589 | attribute_value):
2590 | """
2591 | Return how many qualified elements which has attribute like the following:
2592 |
2593 | """
2594 | count = 0
2595 | for element in self.xml_doc.getElementsByTagName(tag_name):
2596 | if element.hasAttribute(attribute_name) and \
2597 | element.getAttribute(attribute_name) == attribute_value:
2598 | count = count + 1
2599 | return count
2600 |
2601 | def __get_first_element_by_attribute(self, tag_name, attribute_name, \
2602 | attribute_value):
2603 | """
2604 | Return the first element which has attribute like the following:
2605 |
2606 | """
2607 | ret = None
2608 | for element in self.xml_doc.getElementsByTagName(tag_name):
2609 | if element.hasAttribute(attribute_name) and \
2610 | element.getAttribute(attribute_name) == attribute_value:
2611 | ret = element
2612 | return ret
2613 | ####################### Private End #######################################
2614 |
2615 | def pre_check(fname, action, after_key, key, value, indentation):
2616 | """
2617 | Input parameter check
2618 | """
2619 |
2620 | if fname == "":
2621 | msg = "ERROR: Mandatory setting of file are not given"
2622 | print msg
2623 | return False
2624 |
2625 | if action not in ("add", "remove", "update"):
2626 | if action == "":
2627 | msg = "ERROR: Mandatory setting of action are not given"
2628 | else:
2629 | msg = "Action of %s is not supported." % (action)
2630 | print msg
2631 | return False
2632 |
2633 | if key == "":
2634 | msg = "ERROR: Mandatory setting of key are not given"
2635 | print msg
2636 | return False
2637 |
2638 | if action in ("update", "add"):
2639 | if value == "":
2640 | msg = "ERROR: For operation of %s, mandatory setting of value are not given" % (action)
2641 | print msg
2642 | return False
2643 |
2644 | return True
2645 |
2646 | def do_operation(fname, action, after_key, keys, values,
2647 | indentation=INDENTATION):
2648 | """
2649 | Perform the operation on maui xml configuration.
2650 | """
2651 | xml_cfg = AtmosXMLCfg(fname)
2652 |
2653 | if action == "update":
2654 | for k, v in zip(keys, values):
2655 | xml_cfg.update_entry(k, v)
2656 |
2657 | if action == "remove":
2658 | for k in keys:
2659 | xml_cfg.remove_entry(k)
2660 |
2661 | if action == "add":
2662 | for k, v in zip(keys, values):
2663 | xml_cfg.add_entry(after_key, k, v, indentation)
2664 |
2665 | xml_cfg.write_xml_to_file(fname)
2666 |
2667 | def usage():
2668 | _usage = """Usage: %s