Shell 编程常见用法

本文主要记录写 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 脚本的方式

CommandExplanation
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
image.png
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 参数

SAP Help Portal

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`)  # 存储到一个数组

循环遍历

浅谈shell 遍历数组的几种方法_linux shell

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

批量以日期重命名

shell批量以日期重命名文件 - 走看看

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

致谢

感谢上方链接中各位博主的帮助。大家可以去看看,这些方法都是验证过的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值