本文主要记录写 shell 脚本时的常用写法。
目录
规范
- 脚本使用 set -o errexit 开始,使得脚本出错立即停止,避免出现更严重的问题。
- 每个脚本开头必须写清楚解释器。否则在多个环境中默认解释器不同,运行结果也不同。
配置
配置脚本报错立即退出
set -o errexit
# ...
set +o errexit
set -e从根本上解决了这个问题,它使得脚本只要发生错误,就终止执行。
set +e表示关闭-e选项,set -e表示重新打开-e选项。
-e还有另一种写法-o errexit
配置任何一个子命令失败,整个管道命令就失效,脚本终止执行
set -o pipefail
# ...
set +o pipefail
判断操作
若变量未设置则为真
[ -z ${VAR} ]
判断变量不为空
if [ -n "${var}"]; then
echo "not null"
fi
if [ "${var}" = "null" ]; then
echo "var is null"
fi
判断是否等于某字符串
shell脚本判断变量是否包含某个字符串的几种方法_lkdcom的博客-CSDN博客_shell脚本判断字符串是否包含某个字符
if [ "${APPS_CHECK_RESULT}" = "OK" ];then
echo "OK"
elif [ "${APPS_CHECK_RESULT}" = "FAIL" ];then
echo "FAIL"
fi
判断文件中是否包含特定字符串
if [ `grep -c "字符串" 文件路径` -eq '0' ]; then
echo "Found!"
else
echo "error"
fi
判断文件是否存在
if [ -d 文件夹路径 ]; then echo "exist";fi
if [ ! -d 文件夹路径 ]; then echo "missing";fi
判断文件夹是否存在
if [ -d "/data/" ];then
echo "文件夹存在"
else
echo "文件夹不存在"
fi
判断路径是否存在
if [[ -x "${IDF_PATH}" ]]; then
pushd ${IDF_PATH}
local idf_ver=$(git ls-remote --heads origin release/${idf_ver_tag} | grep -o "release/.*")
if [[ -n "$idf_ver" ]]; then
export IDF_VERSION="release/${idf_ver_tag}"
else
export IDF_VERSION="${idf_ver_tag}"
fi
popd
else
echo "IDF_PATH not set or path not exist"
fi
多项判断错误
condition expected
./tools/ci/apps_filter.sh:57: condition expected:
# 如果存在此情况的行是 if 判断语句,则可能是由于多项判断被大括号整体括住了,详情如下:
if [[ xxx ] && [ xxx ]]; then
echo "这是错误的示范"
fi
文件比较符
-e 判断对象是否存在
-d 判断对象是否存在,并且为目录
-f 判断对象是否存在,并且为常规文件
-L 判断对象是否存在,并且为符号链接
-h 判断对象是否存在,并且为软链接
-s 判断对象是否存在,并且长度不为0
-r 判断对象是否存在,并且可读
-w 判断对象是否存在,并且可写
-x 判断对象是否存在,并且可执行
-O 判断对象是否存在,并且属于当前用户
-G 判断对象是否存在,并且属于当前用户组
-nt 判断file1是否比file2新 [ "/data/file1" -nt "/data/file2" ]
-ot 判断file1是否比file2旧 [ "/data/file1" -ot "/data/file2" ]
判断系统是否安装了某软件
if ! type ${name} >/dev/null 2>&1;then
echo "${name} 未安装"
else
echo "${name} 已安装"
fi
比较
shell 浮点数比较大小_51CTO博客_shell 浮点数比较
[root@db03 ~]# echo "10.3 > 10.1" | bc
1
[root@db03 ~]# echo "1.1 < 0.7" | bc
0
# 如果使用 if 判断一定注意使用下方写法
if [ `echo ${var}" > "${array[1]} | bc` = 1 ]; then
echo "> "${array[1]}
else
echo "< "${array[1]}
fi
# 不能使用下方写法
if [ `echo ${var}" > "${array[1]} | bc` ]; then # 这是错误的示范
echo "> "${array[1]}
else
echo "< "${array[1]}
fi
查找
查找排除某个或多个目录的文件
find "要查找的目录路径" ! -path "*/希望排除的目录/*" -type f -name "要查找的文件名"
还可以排除多个目录
find "要查找的目录路径" ! -path "*/希望排除的目录1/*" ! -path "*/希望排除的目录2/*" -type f -name "要查找的文件名"
eg:
find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"
限制目录深度查找文件/文件夹
例如:在下一级目录中查找
find . -maxdepth 1 -name <find-name>
# eg: find . -maxdepth 1 -name esp-adf
仅查找文件夹
加一个参数 -type f。
例如:
- f 普通文件
- d 目录文件
- l 链接文件
- b 块设备文件
- c 字符设备文件
- p 管道文件
- s socket文件
find . -name <find-folder-name> -type d
匹配
grep
匹配数字、浮点数、版本号
# -o 只输出匹配到的内容
echo "v4.4.3" | grep -o "[0-9].*"
仅显示匹配部分
grep 仅显示匹配部分_liuck的博客-CSDN博客_grep只显示匹配内容
grep -o
grep 统计匹配到的内容数量
统计grep查找的字符 一共有多少个匹配_大胖头leo的博客-CSDN博客
grep -o "aaa" file | wc -l
获取
逐行读取文件
while read line
do
echo $line
done < examples.txt
获取找到的匹配文件的数量
NUM=$(ls dir | grep "sdkconfig" | wc -l)
echo ${NUM}
sed 用法
在文件末的下一行添加内容
sed -i '$a\CONFIG_'$1'_BOARD=y' sdkconfig.defaults
,其中 $1 是传入 shell 脚本的第一个参数,sdkconfig.defaults 是需要修改的文件。
去除字符串中的引号
echo \"hello\" | sed 's/\"//g'
替换特定的字符串
是分隔符,用 $3 替换 $2
sed -i "s#$2#$3#" $1
删除文件中特定字符串的操作
sed -i "s/\/Makefile//g" examples.txt
正则表达式
【Linux】【Shell】Shell 正则表达式_RadiantJeral的博客-CSDN博客_shell正则
Linux基础知识(18): Shell编程——正则表达式、字符截取命令、字符处理命令_TechArtisan6的博客-CSDN博客
字符串处理
替换特定字符串
shell 字符串操作 ${} 的截取,删除,和 替换 - 腾讯云开发者社区-腾讯云
# 普通替换
${string/match_string/replace_string}:将 string 中第一个 match_string 替换成 replace_string
${string//match_string/replace_string}:将 string 中的 match_string 全部替换成 replace_string [user@host dir]$ str=123abc123 [user@host dir]$ echo "${str/123/r}" rabc123 [user@host dir]$ echo "${str//123/r}" rabcr
# 前后缀替换
${string/#match_string/replace_string}:将 string 中第一个 match_string 替换成 replace_string
${string/%match_string/replace_string}:将 string 中的 match_string 全部替换成 replace_string [user@host dir]$ str=123abc123 [user@host dir]$ echo "${str/#123/r}" rabc123 [user@host dir]$ echo "${str/%123/r}" 123abcr
# 正则匹配
match_string 可以是一个正则表达式 [user@host dir]$ str=123abc123 [user@host dir]$ echo "${str/3*1/r}" 12r23
以特殊字符分隔字符串为数组
Shell_Linux Shell 中实现字符串切割的几种方法_Baiyi_destroyer的博客-CSDN博客_shell 切割字符串
#!/bin/bash
# 在某些 shell 环境使用 tr 会数组长度出错
string="hello,shell,split,test"
array=(${string//,/}
for var in ${array[@]}
do
echo ${var}
done
查找某文件特定字符串后的内容
cat examples.txt | grep -o 'examples/.*' > example_cp.txt
获取字符串变量特定字符串之后的内容
echo ${result}
echo ${result#*:*:}
查找文件或变量中特定的字符串
result=$(cat ${ADF_PATH}/tools/ci/apps.json | grep -E $line)
# 或
result=$(echo ${board} | grep "${var}")
以特定字符分隔字符串
array=(`echo ${result} | tr ';' ' '` )
for var in ${array[*]}
do
echo ${var}
done
字符串排序
可将相同的字符串紧挨在一起。然后取出重复的字符串。
echo ${var} | sort
字符串排序并去除重复的字符串
echo ${var} | sort -u
运算
awk
除法运算
echo ${ver} 2 | awk '{printf("%d\n",$1/$2)}'
echo ${被除数} ${除数} | awk '{printf("%2.f\n",$1/$2)}'
打印每行的第一个字段
git submodule | grep "esp-idf" | sed -r 's/-(.*) esp-idf/\1/g' | awk '{print $1}'
原本输出为
3c8bc2213cd5719d0c61ae9465a188eac83dfd70 esp-idf (v4.4.4-278-g3c8bc2213c)
使用 | awk '{print $1}'
为
3c8bc2213cd5719d0c61ae9465a188eac83dfd70
整形变量自增
((a++))
echo ${a}
卸载软件
sudo apt-get remove jq
Shell 脚本中调用另一个 Shell 脚本的方式
Command | Explanation |
---|---|
fork | 新开一个子 Shell 执行,子 Shell 可以从父 Shell 继承环境变量,但是子 Shell 中的环境变量不会带回给父 Shell。 |
exec | 在同一个 Shell 内执行,但是父脚本中 exec 行之后的内容就不会再执行了 |
source | 在同一个 Shell 中执行,在被调用的脚本中声明的变量和环境变量, 都可以在主脚本中进行获取和使用,相当于合并两个脚本在执行。 |
颜色
彩色打印
echo -e "\e[1;31m This is red test \e[0m"
说明:
- -e :解释字符串中的转义字符,若不加此选项,转义字符会按照文本直接输出
- \e[1;31m … \e[0m:前景色编号,其中 “\e” 输出Esc符号,也可以用 “\033”;"[1;31m"中,"1"表示粗体(高亮),"31"表示红色,中间用分号隔开,“m"后面为输出文本;”\e[0m"表示将颜色重新置回默认终端颜色
前景色种类:0 透明(使用终端颜色) 30 黑, 31 红, 32 绿, 33 黄, 34 蓝, 35 紫, 36 青绿, 37 白(灰)
背景色种类:0 透明(使用终端颜色) 40 黑, 41 红, 42 绿, 43 黄, 44 蓝 45 紫, 46 青绿, 47 白(灰)
变量
shell 中有两种声明变量的方式
第一种是直接赋值,比如a=1。但是一定要记住,以这种方法命名的变量的类型都是默认的字符串类型。这个为什么很重要我们在后面会说到,但是你一定要记住,默认的类型都是字符串类型。
第二种是使用declare命令。declare命令的格式为 declare [+或者-][选项] 变量名。其中-的含义是赋予变量名特定的属性,而+是取消变量名特定的属性,这点和我们平时的习惯有所不同,但是因为shell中很多命令的选项都是-xxx,相信大家也比较好理解。我们再说选项,选项主要有以下几种:
原文链接:https://blog.csdn.net/weixin_28698129/article/details/113490028
declare -i 变量名称
Json 处理
使用 jq 处理 Json 格式
export ESP_ADF_MODULES='{"adf-libs-ut":"master","esp-adf-libs":""}'
获取 Json 数组的长度
cat apps_news.json | jq length
获取 Json 键值 Key
echo ${ESP_ADF_MODULES} | jq -r keys[]
获取 Key 对应的 Vaule
echo ${ESP_ADF_MODULES} | jq -r '.["adf-lib-ut"]'
获取不带引号的值
# 你会发现这个参数是获取到了但是怎么带了引号,jq 如何去掉引号获取呢?(现在我演示一下如何获取一个类似:{"name":"zmide","id":1234} 中获取 name 并赋值到 shell 变量上 )
# 去掉引号获取可以使用 -r 模式,这里我用了管道符代替文件了
echo '{"name":"zmide","id":1234}' | jq -r .name
# 将获取到的值赋值到 name 变量
name=`echo '{"name":"zmide","id":1234}' | jq -r .name`
echo ${name}
使用 jq 小工具处理 json 文件
sudo apt-get install jq
使用情景:
{
"name": "test",
"AppID": "com.test",
"DisplayName": "demo",
"Version": "1.0",
"Build": 1,
}
jq -c .name ./app.json
jq 部分指令如下:–version
输出 jq 版本并退出。
–seq
使用application/json-seqMIME类型方案在jq的输入和输出中分隔JSON文本。这意味着将在输出的每个值之前打印一个ASCII RS(记录分隔符)字符,并在每个输出之后打印一个ASCII LF(换行)字符。无法解析的输入JSON文本将被忽略(但会发出警告),并丢弃所有后续输入,直到下一个RS。此模式还解析不带–seq选项的jq的输出。
–stream
以流方式解析输入,输出路径和叶值数组(标量和空数组或空对象)。例如,"a"变[[],“a”],并且[[],“a”,[“b”]]成为[[0],[]],[[1],“a”],和[[1,0],“b”]。
这对于处理非常大的输入很有用。将此与过滤以及the reduce和foreach语法结合使用,可逐步减少大输入。
–slurp/ -s
不必为输入中的每个JSON对象运行筛选器,而是将整个输入流读入一个大数组,然后仅运行筛选器一次。
–raw-input/ -R
不要将输入解析JSON。相反,每一行文本都作为字符串传递到过滤器。如果与组合–slurp,则整个输入将作为单个长字符串传递到过滤器。
–null-input/ -n
根本不读任何输入!而是将过滤器null作为输入运行一次。当将jq用作简单计算器或从头开始构造JSON数据时,这很有用。
–compact-output/ -c
默认情况下,jq pretty-prints JSON输出。通过将每个JSON对象放在一行上,使用此选项将导致输出更紧凑。
–tab
为每个缩进级别用一个选项卡,而不是两个空格。
–indent n
使用给定的空格数(不超过8个)进行缩进。
–color-output/ -C 和 --monochrome-output/ -M
默认情况下,如果写入终端,jq将输出彩色的JSON。即使使用写入管道或文件-C,也可以强制其产生颜色,并使用禁用颜色-M。
可以使用JQ_COLORS环境变量配置颜色。
–ascii-output/ -a
jq通常将非ASCII Unicode代码点输出为UTF-8,即使输入将其指定为转义序列(例如“ \ u03bc”)也是如此。使用此选项,您可以强制jq产生纯ASCII输出,并用等效的转义序列替换每个非ASCII字符。
–unbuffered
在打印每个JSON对象之后刷新输出(如果将慢速数据源输送到jq并将jq的输出输送到其他位置,则很有用)。
–sort-keys/ -S
用键按顺序输出每个对象的字段。
–raw-output/ -r
使用此选项,如果过滤器的结果是字符串,则将其直接写入标准输出,而不是将其格式化为带引号的JSON字符串。这对于使jq过滤器与基于非JSON的系统进行通信很有用。
–join-output/ -j
就像,-r但是jq在每个输出之后不会打印换行符。
-f filename/ --from-file filename
从文件而不是从命令行读取过滤器,如awk的-f选项。您也可以使用“#”发表评论。
-Ldirectory/ -L directory
前置directory为模块搜索列表。如果使用此选项,则不使用内置搜索列表。请参阅下面的模块部分。
-e/ --exit-status
设置为0 JQ的退出状态,如果最后输出值既不false也不null,1,如果最后的输出值要么false或null或4,如果没有有效的结果是以往任何时候产生的。通常,如果存在任何使用问题或系统错误,jq退出时为2;如果存在jq程序编译错误,则退出3;如果运行jq程序,则退出0。
设置退出状态的另一种方法是使用halt_error内置功能。
–arg name value
此选项将值作为预定义变量传递给jq程序。如果使用来运行jq --arg foo bar,则
f
o
o
该程序在程序中可用并且具有值
"
b
a
r
"
。请注意,
v
a
l
u
e
它将被视为字符串,因此
−
−
a
r
g
f
o
o
123
将绑定
foo该程序在程序中可用并且具有值"bar"。请注意,value它将被视为字符串,因此--arg foo 123将绑定
foo该程序在程序中可用并且具有值"bar"。请注意,value它将被视为字符串,因此−−argfoo123将绑定foo到"123"。
命名参数也可用于jq程序$ARGS.named。
–argjson name JSON-text
此选项将JSON编码的值作为预定义变量传递给jq程序。如果使用来运行jq --argjson foo 123,则$foo该程序在程序中可用并且具有值123。
–slurpfile variable-name filename
此选项读取命名文件中的所有JSON文本,并将已解析的JSON值数组绑定到给定的全局变量。如果使用来运行jq --slurpfile foo bar,则$foo该程序中可用,并且有一个数组,其元素对应于名为的文件中的文本bar。
–rawfile variable-name filename
此选项读取命名的文件,并将其内容绑定到给定的全局变量。如果使用来运行jq --rawfile foo bar,则$foo该程序中可用,并且有一个字符串,其内容与名为的文件中的tex有关bar。
–argfile variable-name filename
不使用,使用–slurpfile代替。
(此选项类似于–slurpfile,但是当文件只有一个文本时,则使用该文本,否则使用文本数组–slurpfile。)
–args
其余参数是位置字符串参数。这些可作为到jq程序使用$ARGS.positional[]。
–jsonargs
其余参数是位置JSON文本参数。这些可作为到jq程序使用$ARGS.positional[]。
–run-tests [filename]
在给定文件或标准输入中运行测试。这必须是给出的最后一个选项,并且不支持所有前面的选项。输入由注释行,空行和程序行组成,后跟一个输入行,与预期一样多的输出行(每个输出一个)和一个终止的空行。编译失败测试从仅包含“ %% FAIL”的行开始,然后是包含要编译的程序的行,然后是包含要与实际值进行比较的错误消息的行。
命令行中传递 JSON 参数
Shell 脚本参数高级用法
这样处理shell脚本参数,爽多了! - 腾讯云开发者社区-腾讯云
getopt 长参数/长选项用法
shell小技巧–长选项参数getopt用法-腾讯云开发者社区-腾讯云
# Process parameters, normalize parameters
ARGS=`getopt -a -o c:h: --long check:,help -- "$@"`
if [ $? != 0 ];then
echo "Terminating..."
exit 1
fi
# Rearrange parameter order
eval set -- "${ARGS}"
# Processing parameters through shift and while loops
while :
do
case $1 in
-c|--check)
CHECK_TYPE=$2
shift
;;
-h|--help)
usage
;;
--)
shift
break
;;
*)
echo "Internal error!"
exit 1
;;
esac
shift
done
getopts 参数匹配
getopts 使用简单,但无长选项支持
这样处理shell脚本参数,爽多了! - 腾讯云开发者社区-腾讯云
#!/usr/bin/env bash
# -n 名称
# -a 作者
# -h 帮助
while getopts ":n:a:h" optname
do
case "$optname" in
"n")
echo "get option -n,value is $OPTARG"
;;
"q")
echo "get option -a ,value is $OPTARG"
;;
"h")
echo "get option -h,eg:./test.sh -n 编程珠玑 -a 守望先生"
;;
":")
echo "No argument value for option $OPTARG"
;;
"?")
echo "Unknown option $OPTARG"
;;
*)
echo "Unknown error while processing options"
;;
esac
#echo "option index is $OPTIND"
done
解释一下:
- 有两个预先定义的变量,_OPTARG_表示选项值,OPTIND表示参数索引位置,类似于前面提到$1。
- n后面有:,表示该选项需要参数,而h后面没有:,表示不需要参数
- 最开始的一个冒号,表示出现错误时保持静默,并抑制正常的错误消息
数组
Shell数组添加元素注意事项__荣耀之路_的博客-CSDN博客_shell添加数组元素
元素追加。
遍历数组的方法
shell 数组遍历的3种方法_「已注销」的博客-CSDN博客_shell for 数组
shell 数组及其遍历的3种方法_Data_IT_Farmer的博客-CSDN博客_shell 数组
# 注意:数组第一个元素有时从下标 1 开始,也就是 TEST_MODULE_BRANCH[1]
for (( i = 0; i < ${#TEST_MODULE_BRANCH[@]}; i ++ )) do
echo ${TEST_MODULE_BRANCH[i]}
done
循环获取数组中的元素
for num in ${var[*]}
do
#....
done
获取数组的元素个数
echo ${#array[@]}
将排序后的字符串存储到一个数组中
array=`ls | sort` # 这可不是存一个数组。
array=(`ls | sort`) # 存储到一个数组
循环遍历
i=0
while [ $i -lt ${#array[@]} ]
#当变量(下标)小于数组长度时进入循环体
do
echo ${ array[$i] }
#按下标打印数组元素
let i++
done
字符串数字互转
shell 字符串和数字互相转换_小白的进阶的博客-CSDN博客_shell 字符串转数字
# 双括号运算符:
a=$(( 1 + 2 ));
echo $a;
# 等同于:
a=`expr 1 + 2`
Shell 脚本获取 Python 命令的返回结果
shell 脚本如何获取 python 命令返回的结果 | 程序员笔记
#! /bash/sh
python3 -u demo.py
if [ $? -eq 0 ];then
echo '上一个命令执行成功'
else
echo $?
echo '上一个命令执行失败!'
fi
批量以日期重命名
find ./log -name "*.log" | while read file
do
DATE=$(date +%Y%m%d_%H%M%S_%N)
mv $file ./temp_log/${DATE}.log
done
命令结果输出给变量
shell脚本将命令的输出结果赋值给变量_Yellow0523的博客-CSDN博客_shell将命令执行结果赋值给变量
#使用反引号,存入Line变量
line=`cat tempstatus.txt wc-1`
#使用邵(),存入变量
line=$(cat tempstatus.txt wc -1)
#输出Line的行数
echo $line
下载
wget
下载工具
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.0/clang+llvm-16.0.0-86_64-linux-gun-ubuntu-18.04.tar.xz
patch
打 patch
# 方式一
patch -p0 < your.patch
# 方式二
patch -p0 -i your.patch
# 方式三
git apply -p0 your.patch
#这里比较推荐前两种方式,第三种方式有时候打不上。
解释一下 -p0 表示指定的目标文件前没有 a/ b/ 的前缀,这点与 git diff 生成的 patch 不同
patch 结构如下
必备要素为
--- 路径 a
--- 路径 b
@@ -行号,行数 +行号,行数 @@
- 内容
+ 内容
--- 路径 a
+++ 路径 b
@@ -行号,行数 +行号,行数 @@
- 内容
+ 内容
举例
--- components/audio_hal/driver/es8311/es8311.h
+++ components/audio_hal/driver/es8311/es8311.h
@@ -29,49 +29,47 @@
#include "esp_types.h"
#include "esxxx_common.h"
-
-#define ES8311_DAC_VOL_CFG_DEFAULT(a+b) \
- do { \
- .max_dac_volume = 32, \
- .min_dac_volume = -95.5, \
- .board_pa_gain = BOARD_PA_GAIN, \
- .volume_accuracy = 0.5, \
- .dac_vol_symbol = 1, \
- .zero_volume_reg = 0xBF, \
- .reg_value = 0, \
- .user_volume = 0, \
- .offset_conv_volume = NULL, \
- } while(0);
+#define ES8311_DAC_VOL_CFG_DEFAULT(a + b) do { \
+ .max_dac_volume = 32, \
+ .min_dac_volume = -95.5, \
+ .board_pa_gain = BOARD_PA_GAIN, \
+ .volume_accuracy = 0.5, \
+ .dac_vol_symbol = 1, \
+ .zero_volume_reg = 0xBF, \
+ .reg_value = 0, \
+ .user_volume = 0, \
+ .offset_conv_volume = NULL, \
+} while (0);
#ifdef __cplusplus
extern "C" {
--- components/audio_hal/driver/es8311/es8311.h
+++ components/audio_hal/driver/es8311/es8311.h
@@ -320,7 +320,7 @@
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
-esp_err_t es8311_set_mic_gain(es8311_mic_gain_t gain_db) ;
+esp_err_t es8311_set_mic_gain(es8311_mic_gain_t gain_db);
/**
* @brief Print all ES8311 registers
生成 patch 文件
import difflib
formatted_code = StringIO(stdout).readlines()
diff = difflib.unified_diff(code, formatted_code,
filename, filename,
'(before formatting)', '(after formatting)')
diff_string = ''.join(diff)
if len(diff_string) > 0:
sys.stdout.write(diff_string)
错误修复
**BrokenPipeError: **管道重定向导致 stdout 错误
if eval "$diff_command" | $CLANG_FORMAT_DIFF_SCRIPT -p1 | grep -q . &>/dev/null; then
若 $CLANG_FORMAT_DIFF_SCRIPT 中打印没有执行完时,外面的命令直接重定向或者关闭终端会发生以下错误
Traceback (most recent call last):
File "/home/xxx/clang-format-diff.py", line 384, in <module>
main()
File "/home/xxx/clang-format-diff.py", line 373, in main
sys.stdout.write(diff_string)
BrokenPipeError: [Errno 32] Broken pipe
解决方法
不使用管道
diff_result=$(eval "$diff_command")
clang_format_diff_result=$($CLANG_FORMAT_DIFF_SCRIPT -p1 <<< "$diff_result")
if [ -n "$clang_format_diff_result" ]; then
致谢
感谢上方链接中各位博主的帮助。大家可以去看看,这些方法都是验证过的。