Shell常用命令与脚本实例

 
#!/bin/sh
  
echo "Hello shell"
  
# ----------------------字符串---------------------#
  
readonly URL="定义一个常量:www.baidu.com"
  
your_name="jack"
echo $your_name
echo ${your_name}
  
  
for file in `ls ~/Desktop`; do
    echo "${file}"
done
  
echo $URL
  
your_name1='单引号字符串内部不能有变量,只能固定输出'
your_name2="单引号字符串可以有变量${URL},和转义符\"Hi,转义\""
echo $your_name1
echo $your_name2
  
echo "字符串长度:${#your_name}"
echo "子字符串,从1下标开始读3个字符:${your_name:1:3}"
echo `gexpr index "$your_name1" 固定` #语法错误
echo "使用#号可以截取指定字符(或者子字符串)右边的所有字符, *表示跨过左侧任意个字符:${your_name1#*固定}"
echo "使用%号可以截取指定字符(或者子字符串)左边的所有字符, *表示跨过右侧任意个字符:${your_name1%固定*}"
  
#字符串转数组
string="hello,shell,split,test"
#将,替换为空格
array=(${string//,/ })
 
#字符串包含判断
#字符串是否符合正则表达式?
if [[ ${1} == *\.podspec || ${1} == *\.pbxproj || ${1} == *\.plist || ${1} == *\.sh ]];
#字符串包含:父字符串$filterList 是否包含子字符串$item ?
if [[ $filterList =~ $item ]]
  
# ----------------------数组---------------------#
 
cities=("北京" "上海" "深圳" "杭州")
echo ${cities[1]}
 
echo ${cities[@]} # @:获取数组中所有的元素
echo ${!cities[@]} # ![@]:获取数组中所有的元素的key键,数组可以放[key:value]对
echo "数组的长度:${#cities[@]}"
 
# 数组包含判断
# 数组包含:数组$"{filterList[@]}" 是否包含字符串"$item" ?
if [[ "${filterList[@]}" =~ "$item" ]]
# 数组不包含?
if [[ ! "${filterList[@]}" =~ "$item" ]]
 
# 数组添加元素
# 添加方式 语法 可添加多个元素 下标必须连续 添加后下标改变 可能覆盖原有元素
# 直接下标添加 cities[index]=value 否 否 否 是
# 数组长度添加 cities[${#cities[@]}]=value或cities[${#cities[*]}]=value 否 是 否 是
# 重新创建数组 cities=("${cities[@]}" value1 ... valueN) 是 否 是 否
# 赋值运算符+= cities+=(value1 ... valueN) 是 是 是 否
:<<EOF
多行注释: 定义一个函数EOF,但是没有地方调用,达到注释的效果
EOF
 
# ----------------------传递参数---------------------#
 
:<<EOF
$0: 执行文件名
$1: 第一个参数
$2: 第一个参数 . .
EOF
 
echo "执行文件的名称为:$0,传参个数为:$#, 参数值为:$1,$2"
 
# ----------------------运算符执行---------------------#
 
需要获取命令结果返回值的使用下面2种方式
纯命令用``或$()执行 `xcodebuild -list -project aaa.xcodeproj`
带参数用$()执行 $(ls $name)
 
不需要获取命令结果返回值的,直接写命令即可
xcodebuild -list -project aaa.xcodeproj
 
# ----------------------函数---------------------#
 
1、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。
return 后跟数值n(0-255)
3、函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数,超过10个用${11}
 
funWithParam(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
     echo "第十个参数为 $10 !"
     echo "第十个参数为 ${10} !"
     echo "第十一个参数为 ${11} !"
     echo "参数总数有 $# 个!"
     echo "作为一个字符串输出所有参数 $* !"
}
 
funWithParam 1 2 3 4 5 6 7 8 9 34 73
结果:
第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !
 
# ----------------------逻辑运算---------------------#
 
单中括号[],双中括号[[]],小括号(())的区别?
if [[ $a > $b ]] 双中括号支持正则表达式
if [ $a > $b ] 单中括号不支持正则表达式
if (( a > b )) 小括号不用使用$做取值了
 
 
判断:大于,小于,等于,不等于。
在比较时,数字和字符串可以使用不同的比较符号
比较数字 (numberic):-ne
比较字符 (string):!=
多条件使用|| 或者 &&
 
1.如果a>b且a<c
if [[ $a > $b ]] && [[ $a < $c ]]
或者
if [ $a -gt $b -a $a -lt $c ]
 
if (( a > b ));
then
...
else
# 如果else里没有处理语句,则else不能写
fi
  
if [ $subCmd == $subCmdValue1 ]; then
fi
if [ ${projName} != "Pods" ]; then
fi
  
判断:非空判断 不为空
if空判断
if [ ! -n "$a" ]; then
echo "IS NULL"
else
echo "NOT NULL"
fi
 
if [ ! $a ]; then
echo "IS NULL"
else
echo "NOT NULL"
fi
 
# ----------------------文件目录---------------------#
 
shell 目录,文件判断
-f "file" : 判断file是否是文件;
-d "file" : 判断file是否是目录(文件夹)。
:<<EOF
xargs 将标准输入作为下一条命令的参数 $
echo "hello world" | xargs echo hello world
上面的代码将管道左侧的标准输出,转为命令行参数hello world,传给第二个echo命令。
EOF
 
 # ----------------------循环遍历---------------------#
 
 sortSchemeNames=(aaa bbb ccc)
 projInfo=`xcodebuild -list -project aa.xcodeproj`
 #目标字符串projInfo中,#*中间间隔任意个字符串直到查到“Schemes:”字符串,返回其右侧的部分
 tragetSchemes=${projInfo#*Schemes:}
 for ((i=0; i<${#schemeNames[@]}; i++)); do
    scheme=schemeNames[i]
    # 父字符串$tragetSchemes 是否包含子字符串$scheme ?
    if [[ $tragetSchemes =~ $scheme ]] then
        echo "------------第${i}个库构建开始:${scheme}"
        echo "++++++++++++第${i}个库构建结束:${scheme} \n"
    fi
 done
 
 for scheme in ${sortSchemeNames[@]}; do
    if [[ $tragetSchemes =~ $scheme ]] then
        echo "----------> build 开始:${scheme}"
        echo "<---------- build 结束:${scheme} \n"
    fi
 done
 
 # ----------------------路径截取---------------------#
 
 :<<EOF
 
 shell之文件路径截取 file=/dir1/dir2/dir3/my.file.txt
 我们可以用${ }分别替换获得不同的值:
 
 ${file#*/}:拿掉第一条/及其左边的字串:dir1/dir2/dir3/my.file.txt
 ${file##*/}:拿掉最后一条/及其左边的字串:my.file.txt
 ${file#*.}:拿掉第一个.及其左边的字串:file.txt
 ${file##*.}:拿掉最后一个.及其左边的字串:txt
 ${file%/*}:拿掉最后条/及其右边的字串:/dir1/dir2/dir3
 ${file%%/*}:拿掉第一条/及其右边的字串:(空值)
 ${file%.*}:拿掉最后一个.及其右边的字串:/dir1/dir2/dir3/my.file
 ${file%%.*}:拿掉第一个.及其右边的字串:/dir1/dir2/dir3/my
 
 引用地址:http://www.jb51.net/article/94355.htm
 
 EOF
 
 # ----------------------数学运算---------------------#
整数运算使用:(())
小数运算使用:bc
另外:expr(可用于整数运算,也可以处理字符串。比较麻烦)
 
 
语法格式为:((表达式))
表达式可以只有一个,也可以有多个。如果是多个表达式,那么多个表达式之间以逗号,分隔。它们以最后一个表达式的值作为整个 (( )) 命令的执行结果。可以使用$获取 (( )) 命令的结果,这和使用$获得变量值是类似的。
变量赋值: a=$((10+66) b=$((a-15))
逻辑运算: ((a>7 && b==c))
多表达式: ((a=3+5, b=a+10))
在 (( )) 中使用变量无需加上$前缀,(( )) 会自动解析变量名
 
 
bc 是 Linux 下的一个计算器程序,可以处理整数和小数。Shell 本身只支持整数运算,想计算小数就得使用 bc 这个外部的计算器。
Linux bc 命令的语法格式为:
command "表达式" | bc
 
i=10
echo $i
j=3;
echo $j
 
m=`expr $i / $j`
echo $m
 
n=`echo "scale=9; $i / $j" | bc`
echo $n
scale是指定精度,而且只有在除法的时候才有生效,其他都是安装原来都有几位就输出几位;bc支持除了位操作的所有运算。
 
 
expr 是一款表达式计算工具,可用于整数运算,也可以处理字符串
Shell expr 命令的语法格式为:
$(expr variable + variable) 或者 `expr variable + variable`
表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2
 
i=10
echo $i
 
i=`expr $i + 10` #20
echo $i
 
 
# 加减乘除运算
# 乘法
r=`expr 4 \* 5`
r=$(( 4 * 5 ))
r=$[ 4 * 5 ]
echo $r
  
# 除法
r=`expr 40 / 5`
r=$(( 40 / 5 ))
r=$[ 40 / 5 ]
echo $r
  
# 减法
r=`expr 40 - 5`
r=$(( 40 - 5 ))
r=$[ 40 - 5 ]
echo $r
  
# 求余数
r=$[ 100 % 43 ]
echo $r
  
# 乘幂 (如 2 的 3 次方)
r=$(( 2 ** 3 ))
r=$[ 2 ** 3 ]
echo $r

 # ----------------------多条命令一起执行---------------------#

“;”隔开,多条指令无论成败,都会执行
cd /home/PyTest/src; python suning.py

“&&”隔开,多条指令前面的成功了后面才执行

“||”隔开,或,多条指令前面的执行失败,后面才执行

“|”隔开,管道符,多条指令无论成败,都会执行

 

脚本案例

批量编译项目Target依赖的所有子Schemes
# 产物默认目录下~/Library/Developer/Xcode/DerivedData/*
# -destination generic/platform=iOS \
# -destination generic/platform=iphonesimulator\
 
plateformDevice='generic/platform=iOS'
plateformSim='generic/platform=iphonesimulator'
 
# 1.获取工程下所有的schemes, 遍历构建所有子项目
# 假设脚本在工程的父级目录
projectName="aa.xcodeproj"
projectPath=$(find . -name $projectName)
projectPath=${projectPath%/*}
cd $projectPath
 
projInfo=$(xcodebuild -list -project $projectName)
targetSchemes=${projInfo#*Schemes:}
 
for ((i=0; i<${#sortSchemeNames[@]}; i++)); do
    scheme=${sortSchemeNames[i]}
    if [[ $targetSchemes =~ $scheme ]]
    then
        echo "------------构建开始:${scheme}"
        xcodebuild \
        -destination ${plateformDevice} \
        -workspace ${param1}.xcworkspace \
        -scheme ${scheme} \
        -configuration 'Debug'
        echo "++++++++++++构建结束:${scheme} \n"
    fi
done
 

 

真机,模拟器分别归档,并打.xcframework包
# 真机,模拟器分别归档,并打.xcframework包
# 假设脚本在工程的当前目录
# 执行shell命令,查询当前目录下所有的*.xcodeproj文件
projPaths=$(find . -name *.xcodeproj)
projPath0=${projPaths[0]} # 获取第0个路径
projName=${projPath0##*/} # 获取xxx.xcproj工程名
onlyName=${projName%.*}   # 获取纯净的xxx工程名
 
 
xcodebuild archive \
    -scheme ${onlyName} \
    -sdk iphonesimulator \
    -archivePath "archives/ios_sim.xcarchive" \
    BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
    SKIP_INSTALL=NO
 
 
 
xcodebuild archive \
    -scheme ${onlyName} \
    -sdk iphoneos \
    -archivePath "archives/ios_device.xcarchive" \
    BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
    SKIP_INSTALL=NO
 
 
 
xcodebuild -create-xcframework \
    -framework archives/ios_device.xcarchive/Products/Library/Frameworks/${onlyName}.framework \
    -framework archives/ios_sim.xcarchive/Products/Library/Frameworks/${onlyName}.framework \
    -output build/${onlyName}.xcframework

 

批量查询与批量替换脚本例子
#!/bin/sh

filterList=("Pods" "libs" "Scripts" "Makefile" "Podfile" "Podfile.lock" "readme.md" "LEGAL.md" "Assets.xcassets" "xcshareddata" "xcuserdata" "build" "Images.xcassets" "Resources" "Products")
#filterFileList=(*.podspec)

# 如果没有输入cp参数,提示输入cp参数
paramNum=$#
subCmd=$1
param1=$2
param2=$3
readonly location=`pwd`
tempPath=""
subCmdValue1="s" #search
subCmdValue2="r" #replace

searchTotalCount=0



# ------------------search 查询-------------------


function checkFileAndDir() {
    searchPath=`pwd`

    # -iname:忽略大小写;-name:区分大小写;
    find ${searchPath} -iname $1
    
    echo "查询根目录:${searchPath}"
    items=`ls`
    #字符串转数组,将\n替换为空格
#    items=(${items//\n/ })
    echo $items
    index=0
    for item in `ls`; do
        index=`expr $index + 1`
        echo "\n++++++++开始查询第:${index}个项目,项目名称:${item}  ++++++++\n"
        searchOneDir $item
    done
}
        

function searchOneDir(){
    if [ -f ${1} ]; then
    
        if [[ ${1} == *\.podspec || ${1} == *\.pbxproj || ${1} == *\.plist || ${1} == *\.sh ]]; then
            return
        fi
        
#        echo "查询 ${1}"
        res=$(sed -n "/${param1}/Ip" ${1}) #I:取消大小写
#        res=$(sed -n "/${param1}/p" ${1})
        # 非空判断
        if [ -n "$res" ]; then
            searchTotalCount=`expr $searchTotalCount + 1`
            echo "\n递归目录------结果个数:${searchTotalCount} --------:$1 ;"
            echo $res
        fi
        
    elif [ -d ${1} ];then
        #sed -i "" "s/aaa/bbb/g" grep -rl aaa ./
        #grep -rl: l列出文件内容符合条件的文件名, r递归查询
        #$(grep -rl ${param1} ./ | xargs sed -n "/${param1}/Ip")
        
        if [[ ! "${filterList[@]}" =~ "${1}" ]]
        then
            items=$(ls $1)
    #        echo "递归目录------结果个数:${searchTotalCount}--------:$1 ;"
            for item in ${items[@]}; do
    #        for ((i=0; i<${#items[@]}; i++)); do
    #            item=${items[i]}

                # [[ $filterList =~ $item ]]字符串包含:父字符串$tragetSchemes 是否包含子字符串$scheme ?
                # [[ "${filterList[@]}" =~ "$item" ]]数组包含:数组$"{filterList[@]}" 是否包含字符串"$item" ?
                # [[ ! "${filterList[@]}" =~ "$item" ]]数组不包含?

                if [[ ! "${filterList[@]}" =~ "$item" ]]
                then
    #                echo "进入:$item"
                    searchOneDir "$1/$item"
                fi
             done
        fi
    fi
    return 0;
}


# ------------------replace 替换-------------------

function scannerOneDir(){
    echo "${1}"
    if [ -f ${1} ]
    then
#        if [[ ${1} == *\.podspec || ${1} == *\.sh ]]; then
#            return
#        fi
        
        echo "替换 ${1}"
        sed -i "" "s/${param1}/${param2}/g" ${1}
        echo "替换成功"
    elif [ -d ${1} ]
    then
        #sed -i "" "s/aaa/bbb/g" grep -rl aaa ./
        $(grep -rl ${param1} ./ | xargs sed -i "" "s/${param1}/${param2}/g")
    fi
    return 0;
}

function handle() {
    if [ $subCmd == $subCmdValue1 ]; then
       searchOneDir $1;
    else
       scannerOneDir $1;
    fi
}

function handleDir() {
    # 进入到目标目录里,进行替换
    if [[ ! "${filterList[@]}" =~ "$1" ]]
    then
        if [[ ${1} == *\.podspec || ${1} == *\.sh ]]; then
            echo "匹配失败:${1}"
        else
            echo "匹配成功:${1}"
            handle ${1};
        fi
    else
        echo "匹配失败:${1}"
    fi
}
 
function scanDir(){

    res=`find . -name *.xcodeproj`
    echo $res
    if [[ ! ${res} ]]
    then
        # 扫描的是一个普通文件夹
        for item in `ls`; do
            handleDir ${item};
        done
    else
        # 扫描的是一个xcode项目父文件夹
        for path in ${res[@]}; do
            pathT=${path%.*}
            tempPath=${pathT%/*}
            projName=${pathT##*/}
            if [ ${projName} != "Pods" ]
            then
                echo "------进入项目根目录:${tempPath}, 入参:${param1}, ${param2}"
                cd ${tempPath}
                echo "projName: ${projName}"
                for item in `ls`; do
                    handleDir ${item};
                done

                cd ${location}
                echo "++++++退回Ant目录:${location}\n"
            fi
        done
    fi
    return 0;
}



# <<的用法:
# 当shell看到<<的时候,它就会知道下一个词是一个分界符。
# 在该分界符以后的内容都被当作输入,直到shell又看到该分界符(位于单独的一行)。
# 这个分界符可以是你所定义的任何字符串。

# EOF与<<结合:
# 通常将EOF与<<结合使用,表示后续的输入作为子命令或子Shell的输入,直到遇到EOF为止,再返回到主调Shell

# EOF特殊用法:
#EOF是(END Of File)的缩写,表示自定义终止符。既然自定义,那么EOF就不是固定的,可以随意设置别名,在linux按ctrl-d 就代表EOF。
#EOF一般会配合cat能够多行文本输出。
#其用法如下:
#<<EOF        #开始
#....         #输入内容
#EOF          #结束

#熟悉几个特殊符号:
#<:输入重定向
#>:输出重定向
#>>:输出重定向,进行追加,不会覆盖之前内容
#<<:标准输入来自命令行的一对分隔号的中间内容

# :<<COMMENTBLOCK
# shell脚本代码段
# COMMENTBLOCK
# 用来注释整段脚本代码。 :是shell中的空语句。


:<<EOF
shell 目录,文件判断
-f "file"   :  判断file是否是文件;
-d "file"  :  判断file是否是目录(文件夹)。
EOF

:<<EOF
xargs 将标准输入作为下一条命令的参数
$ echo "hello world" | xargs echo
hello world
上面的代码将管道左侧的标准输入,转为命令行参数hello world,传给第二个echo命令。
EOF


if [ $paramNum -lt 2 ]
then
   echo "请输入查询的字符串与要替换的新字符串"
else
    if [ $subCmd == $subCmdValue1 ]; then
        param1=$2
        param2=$3
        echo "开始查询:${param1}"
        checkFileAndDir ${param1}
    elif [ $subCmd == $subCmdValue2 ]; then
        param1=$2
        param2=$3
        echo "查询的字符串:${param1},要替换的新字符串:${param2}"
        scanDir
    else
        param1=$1
        param2=$2
        echo "查询的字符串:${param1},要替换的新字符串:${param2}"
        scanDir
    fi
    
fi

 

 

 

posted @ 2023-02-22 21:25  滴水微澜  阅读(89)  评论(0编辑  收藏  举报