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

浙公网安备 33010602011771号