├── .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 |
10 |
linkedin
11 |
github
12 |
slack
13 |
14 | 15 |

16 | PRs Welcome 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 | linkedin 121 | github 122 | slack 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