Shell script wiki
Table of Contents
1 loop
下面的例子里,第一个 SERVICE_NAME
是一个数组。每二个我也不知道是啥,
反正可以用。推荐使用第一种方式。
SERVICE_NAME=(api ess collect registry ras-cluster) loop() { echo "Clean RCS service." for service in "${SERVICE_NAME[@]}" do echo $service done } loop echo "######" echo ${SERVICE_NAME[1]} echo "${SERVICE_NAME[@]}" SERVICE="api ess collect registry ras-cluster" for i in $SERVICE; do echo $i/bin done
2 老一点的shell中的loop
使用busybox时,需要这样做:
for i in `seq 1 5`;do echo $i;done
3 shell脚本中的判断
下面的版本应该选择哪一个:
has_gunzip=1 if [ $has_gunzip = 1 ]; then echo 'yes' else echo 'no' fi if [[ $has_gunzip = 1 ]]; then echo 'yes' else echo 'no' fi if [[ $has_gunzip == 1 ]]; then echo 'yes' else echo 'no' fi if [ $has_gunzip == 1 ]; then echo 'yes' else echo 'no' fi if [ "$has_gunzip" == 1 ]; then echo 'yes' else echo 'no' fi
看下下面的例子:
bash-4.4$ x=1 bash-4.4$ [ $x = 1 ] && echo y y bash-4.4$ unset x bash-4.4$ [ $x = 1 ] && echo y bash: [: =: unary operator expected bash-4.4$ [[ $x = 1 ]] && echo y bash-4.4$ [ $x = 1 ] && echo y bash: [: =: unary operator expected bash-4.4$ [ "$x" = 1 ] && echo y bash-4.4$ x=1 bash-4.4$ [ "$x" = 1 ] && echo y y bash-4.4$ [ $x = 1 ] && echo y y bash-4.4$ [[ $x = 1 ]] && echo y y bash-4.4$ [[ "$x" = 1 ]] && echo y y bash-4.4$
原因:在很老的bash上只有
[ $x = 1 ]
这种单个中括号的。如果里面判断的变量未定义,直接使用这种方式会报错。 需要这样
[ "$x" = 1 ]
新的bash支持
[[ $x=1 ]]
这种,它在x没有定义时也不会报错。
至于一个等号还是两个。好像是都可以的。
所以推荐使用:
if [ "$has_gunzip" = 1 ]; then echo 'yes' else echo 'no' fi
这种方式。兼容性最好。
下面是bash的man page:
string1 == string2 string1 = string2 True if the strings are equal. = should be used with the test command for POSIX conformance. When used with the [[ command, this performs pattern matching as described above (Compound Com- mands). test expr [ expr ] Return a status of 0 (true) or 1 (false) depending on the evaluation of the conditional expression expr. Each operator and operand must be a separate argument. Expressions are composed of the primaries described above under CONDITIONAL EXPRESSIONS. test does not accept any options, nor does it accept and ignore an argument of -- as signifying the end of options. Expressions may be combined using the following operators, listed in decreasing order of precedence. The evaluation depends on the number of arguments; see below. Operator precedence is used when there are five or more arguments. ! expr True if expr is false. ( expr ) Returns the value of expr. This may be used to override the normal precedence of operators. expr1 -a expr2 True if both expr1 and expr2 are true. expr1 -o expr2 True if either expr1 or expr2 is true. test and [ evaluate conditional expressions using a set of rules based on the number of arguments. 0 arguments The expression is false. 1 argument The expression is true if and only if the argument is not null. 2 arguments If the first argument is !, the expression is true if and only if the second argument is null. If the first argument is one of the unary conditional operators listed above under CONDI- TIONAL EXPRESSIONS, the expression is true if the unary test is true. If the first argument is not a valid unary conditional operator, the expression is false. 3 arguments The following conditions are applied in the order listed. If the second argument is one of the binary conditional operators listed above under CONDITIONAL EXPRESSIONS, the result of the expression is the result of the binary test using the first and third arguments as operands. The -a and -o operators are considered binary operators when there are three arguments. If the first argument is !, the value is the negation of the two-argument test using the second and third arguments. If the first argument is exactly ( and the third argument is exactly ), the result is the one-argument test of the second argument. Otherwise, the expression is false. 4 arguments If the first argument is !, the result is the negation of the three-argument expression composed of the remaining arguments. Otherwise, the expression is parsed and evaluated according to precedence using the rules listed above. 5 or more arguments The expression is parsed and evaluated according to precedence using the rules listed above. When used with test or [, the < and > operators sort lexicographically using ASCII ordering. [[ expression ]] Return a status of 0 or 1 depending on the evaluation of the conditional expression expression. Expressions are composed of the primaries described below under CONDITIONAL EXPRESSIONS. Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed. Conditional operators such as -f must be unquoted to be recognized as primaries. When used with [[, the < and > operators sort lexicographically using the current locale. When the == and != operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below under Pattern Matching, as if the ext- glob shell option were enabled. The = operator is equivalent to ==. If the nocasematch shell option is enabled, the match is performed without regard to the case of alphabetic characters. The return value is 0 if the string matches (==) or does not match (!=) the pattern, and 1 otherwise. Any part of the pattern may be quoted to force the quoted portion to be matched as a string. An additional binary operator, =~, is available, with the same precedence as == and !=. When it is used, the string to the right of the operator is considered an extended regular expression and matched accordingly (as in regex(3)). The return value is 0 if the string matches the pattern, and 1 otherwise. If the regular expression is syntactically incorrect, the conditional expression's return value is 2. If the nocasematch shell option is enabled, the match is performed without regard to the case of alphabetic characters. Any part of the pattern may be quoted to force the quoted portion to be matched as a string. Bracket expressions in regular expressions must be treated carefully, since normal quoting characters lose their meanings between brack- ets. If the pattern is stored in a shell variable, quoting the variable expansion forces the entire pattern to be matched as a string. Substrings matched by parenthesized subexpressions within the regular expression are saved in the array variable BASH_REMATCH. The element of BASH_REMATCH with index 0 is the portion of the string matching the entire regular expression. The element of BASH_REMATCH with index n is the portion of the string matching the nth parenthesized subexpression. Expressions may be combined using the following operators, listed in decreasing order of precedence: ( expression ) Returns the value of expression. This may be used to override the normal precedence of operators. ! expression True if expression is false. expression1 && expression2 True if both expression1 and expression2 are true. expression1 || expression2 True if either expression1 or expression2 is true. The && and || operators do not evaluate expression2 if the value of expression1 is sufficient to determine the return value of the entire conditional expression.
这里 有更细的说明:
To elaborate on bollovan's answer... There is no >= or <= comparison operator for strings. But you could use them with the ((...)) arithmetic command to compare integers. You can also use the other string comparison operators (==, !=, <, >, but not =) to compare integers if you use them inside ((...)). Examples Both [[ 01 -eq 1 ]] and (( 01 == 1 )) do integer comparisons. Both are true. Both [[ 01 == 1 ]] and [ 01 = 1 ] do string comparisons. Both are false. Both (( 01 -eq 1 )) and (( 01 = 1 )) will return an error. Note: The double bracket syntax [[...]] and the double parentheses syntax ((...)) are not supported by all shells.
3.1 总结
以string的方式来对比的话,下面几种方式是相同的,一个中括号和两个中 括号没有区别。一个和两个等号也没有区别:
echo '**************** [[ 01 == 1 ]] ****************' if [[ 01 == 1 ]]; then echo'True' else echo 'False' fi echo '**************** [[ 01 = 1 ]] ****************' if [[ 01 = 1 ]]; then echo'True' else echo 'False' fi echo '**************** [ 01 == 1 ] ****************' if [ 01 == 1 ]; then echo'True' else echo 'False' fi echo '**************** [ 01 = 1 ] ****************' if [ 01 = 1 ]; then echo 'True' else echo 'False' fi echo '**************** [ 1 == 1 ] ****************' if [ 1 == 1 ]; then echo 'True' else echo 'False' fi
不是所有的shell都支持两个中括号的形式:
[[ x=1 ]]
以数值来比,就没有一个等号说法:
if (( 1 == 1 )); then echo 'True' else echo 'False' fi if [[ 1 -eq 1 ]]; then echo 'True' else echo 'False' fi
最后,多看下这个:
Both [[ 01 -eq 1 ]] and (( 01 == 1 )) do integer comparisons. Both are true. Both [[ 01 == 1 ]] and [ 01 = 1 ] do string comparisons. Both are false. Both (( 01 -eq 1 )) and (( 01 = 1 )) will return an error.
4 shell中的判断有时候可以不用写if,直接一行搞定
判断是否是file还是dir
[ -f /tmp ] && echo "yes it is a file" || echo "no it is not a file" [ -d /tmp ] && echo "yes it's a directory" || echo "no is's not a directory"
5 把标准输出给多个管道做为标准输入
zsh下可以这样:
touch /tmp/1 /tmp/2 ls /tmp/ > >(grep 1) > >(grep 2)
6 shell中去掉前缀和后缀
foo=/Users/pengpengxp/Library/Application\ Support/Karabiner/private.xml HOME=`echo ~` suffix="private.xml" foo=${foo#$HOME/} foo=${foo%$suffix} echo $foo
7 数组
FILES=( ~/.bashrc ~/.peng_bashrc ~/.zshrc ~/.mutt ~/.muttrc ~/.slate ~/.ssh ~/.stardict ~/.tigrc ~/.tmux.conf ~/.vimrc ~/.zsh ) for f in "${FILES[@]}" do echo "================backup $f================" done
读取数组的一般格式是这样的:
${array_name[index]}
a=(A B C D) echo ${a[0]} echo ${a[1]} echo ${a[2]} echo ${a[3]}
使用 @
或 *
可以获取数组中的所有元素:
a=(A B C D) echo ${a[@]} echo ${a[*]}
获取数组长度的方法与获取字符串长度的方法相同:
a=(A B C D) echo ${#a[@]} echo ${#a[*]}
8 得到脚本存放的目录
脚本目录加入 PATH
变量后,可以在任何地方运行脚本。那么怎么得到脚本
存放的地址呢? $0
里面其实就存放是脚本的绝对地址啦。把下面脚本加入
PATH
路径中的一处,然后在任何地方试试?都会输出脚本的绝对路径的。
#!/bin/bash echo $0
9 脚本中使用cat输入很多内容
下面这样的 EOF
可以换为其它,只要两个对应得上就可以。
cat << EOF > /tmp/kk xiwapnefwfwajf EOF
10 根据进程是否启动来作不同的处理
#!/bin/bash mkdir -p ~/.rtags/rtags_db function run() { echo "start rdm server." rdm --socket-file=~/.rtags/rdm_socket \ --no-rc \ --data-dir=~/.rtags/rtags_db \ --log-file=~/.rtags/rtags.log \ --crash-dump-file=crash_dump.txt \ --job-count=12 \ --watch-sources-only \ --sandbox-root=~/ & } pgrep "^rdm$" && echo "rdm is already running." && exit 1 pgrep "^rdm$" || echo "start rdm server." && run
11 方便地取得传入的参数
option=${1:-"start"} if [ $option = "start" ]; then echo "start" elif [ $option = "install" ]; then echo "install" elif [ $option = "debug" ]; then echo "debug" elif [ $option = "uninstall" ]; then echo "uninstall" else echo "unknown" exit 127 fi