Some Shell Tricks

shell进阶

1. shell字符串操作

截取操作

f="path1/path2/file.ext"
len="${#f}" # = 20 (字符串长度)
# 切片操作: ${<var>:<start>} or ${<var>:<start>:<length>}
slice1="${f:6}" # = "path2/file.ext"
slice2="${f:6:5}" # = "path2"
slice3="${f: -8}" # = "file.ext"(注意:"-"前有空格)
pos=6
len=5
slice4="${f:${pos}:${len}}" # = "path2" 

替换操作

f="path1/path2/file.ext"
single_subst="${f/path?/x}"   # = "x/path2/file.ext"
global_subst="${f//path?/x}"  # = "x/x/file.ext"
# 字符串拆分
readonly DIR_SEP="/"
array=(${f//${DIR_SEP}/ })
second_dir="${arrray[1]}"     # = path2 

删除头部或尾部

$ a="x y"
$ echo ${a/ */}  # output: x
$ echo ${a/x /z} # output: zy
$ echo ${a% y}  # output: x 从后匹配百分号之后的串,并删除
$ echo ${a#* }  # output: y 从前匹配百分号之后的串,并删除,可以用通配符如*

f="path1/path2/file.ext"
# 删除字符串头部
extension="${f#*.}"  # = "ext"
# 以贪婪匹配方式删除字符串头部
filename="${f##*/}"  # = "file.ext"
# 删除字符串尾部
dirname="${f%/*}"    # = "path1/path2"
# 以贪婪匹配方式删除字符串尾部
root="${f%%/*}"      # = "path1"

2. if [[ ]] 正则表达式

$ platform="android-armeabi-v7a"
$ if [[ $platform == "android"* ]];  # match
$ if [[ $platform =~ "arm" ]];  # match,可以不加引号
$ if [[ $platform == "arm" ]];  # not match
$ if [[ $platform == *"arm"* ]];  # match

3. 判断目录是否存在,不存在Do sth

[ ! -d ${INSTALL_DIR} ] && mkdir -p ${INSTALL_DIR}
# ln is very tricky:
[ ! -d apk ] && ln -s src/android/app/build/outputs/apk apk  # link dir, if dir exists will create apk/apk WRONG!
ln -s ../src/android/app/build/outputs/apk/app-arm64-debug.apk apk/app-arm64-debug.apk  # above is better

4. pushd popd进某目录做事再返回

mkdir -p ${BUILD_DIR}/build_glog
pushd ${BUILD_DIR}/build_glog
cmake $param -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} ${SRC_DIR}/../glog/
make -j${N_JOBS} || exit 1
make install
popd

5. 判断变量是否存在

if [ -z "$NDK_ROOT" ] && [ "$#" -eq 0 ]; then  # -z 判断环境变量;if可以用&&
    echo 'Either $NDK_ROOT should be set or provided as argument'
    echo "e.g., 'export NDK_ROOT=/path/to/ndk' or"
    echo "      '${0} /path/to/ndk'"
    exit 1
else
    NDK_ROOT="${1:-${NDK_ROOT}}"  # ":-"表示 存在则:默认更新为传入的$1,否则还等于原值
fi

6. for循环的用法

#!/bin/bash
for((i=1; i<=10; i++));do echo $(expr $i \* 4);done
for i in {1..5}
for i in $(seq 2 $n)
awk 'BEGIN{for(i=1; i<=10; i++) print i}'  # AWK中的for写法和C语言一样

list=($@)  # get input parameter's list
for i in ${list[@]}; do  # loop over the parameters
  echo "Processing $i..."
done

7. 使用cat«EOF代替echo -e进行多行输出

cat << EOF >> a.txt  # 输出到a.txt, 或者直接打印到屏幕
      Usage:
      1. For master:
      	 \$var
      	 ...
      2. For slave:
         ...
EOF  # 当然也不必用EOF,用AAA等也可以,只是个标识;必须顶格写

8. read -p “Press Enter to continue…”

9. 使用getopt parse输入参数

#!/bin/bash
ARGS=`getopt -o hp:i -l "help,port:,intOrnot" -- "$@"`
eval set -- "${ARGS}"
usage() {
    echo "usage:start.sh -h -p 6692 -i"
}
port=6692
isInt=false

while true;
do
    case "$1" in
        --port|-p)
            fkp_port=$2
            shift 2
            ;;
        --help|-h)
            usage
            exit 0
            ;;
        --intOrnot|-i)
            isInt=true
            shift 1
            ;;
        --)
            shift
            break
            ;;
        *)
            echo "error!"
            exit 1
            ;;
    esac
done

10. android-accept-license.sh

#!/usr/bin/expect -f

set timeout 1800
set cmd [lindex $argv 0]
set licenses [lindex $argv 1]

spawn {*}$cmd
expect {
  "Do you accept the license '*'*" {
        exp_send "y\r"
        exp_continue
  }
  eof
}

11. sed命令:正则表达式

echo "Point 5:  [237, 1051]" | sed 's/.*\[\(.*\)\]/\1/'  # output: 237, 1051,打印匹配的模式(括号内)
Loading Disqus comments...
Table of Contents