Linux Shell判断是否包含字符串的几种方法

本文介绍了在bash脚本中检查子字符串的五种方法:使用grep、字符串运算符、通配符、casein语句以及替换操作。还提供了查找文件中特定字符的示例。

在 bash 脚本中,有不止一种检查子字符串的方法,我们今天介绍一些简单的例子,然后在分享一个常用的 bash 脚本。

3e9dbbb57a8ff4189ef7fce955c33b0a.jpeg

我们在写 bash 脚本的时候,假如有一个字符串,我们想检查其中是否包含另一个子字符串,那这个时候需要怎样做呢?这里介绍Shell判断字符串包含关系的几种方法

   1、通过grep来判断:

str1="abcdefgh"
str2="def"
result=$(echo $str1 | grep "${str2}")
if [[ "$result" != "" ]]
then
    echo "包含"
else
    echo "不包含"
fi

   先打印长字符串,然后在长字符串中 grep 查找要搜索的字符串,用变量result记录结果,如果结果不为空,说明str1包含str2。如果结果为空,说明不包含。这个方法充分利用了grep 的特性,最为简洁。

   2、字符串运算符

str1="abcdefgh"
str2="def"
if [[ $str1 =~ $str2 ]]
then
    echo "包含"
else
    echo "不包含"
fi

   利用字符串运算符 =~ 直接判断str1是否包含str2。

3、利用通配符

str1="abcdefgh"
str2="def"
if [[ $str1 == *$str2* ]]
then
    echo "包含"
else
    echo "不包含"
fi

用通配符*号代理str1中非str2的部分,如果结果相等说明包含,反之不包含。

   4、利用case in 语句

str1="abcdefgh"
str2="def"
case $str1 in 
    *"$str2"*) echo Enemy Spot ;;
    *) echo nope ;;
esac

   5、利用替换

str1="abcdefgh"
str2="def"
if [[ ${str1/${str2}//} == $str1 ]]
    then
       echo "不包含"
    else
      echo "包含"
fi

注意下文中的用的是[[]]还是[]

Shell判断文件是否包含给定字符串

给定一个字符,比方说“Hello Weijishu”,查找相应文件中是否包含该字符。

方式1:grep

# grep -c 返回 file中,与str匹配的行数
grep -c str file




FIND_FILE="/home/linduo/test/Test.txt"
FIND_STR="Hello Weijishu"
# 判断匹配函数,匹配函数不为0,则包含给定字符
if [ `grep -c "$FIND_STR" $FIND_FILE` -ne '0' ];then
    echo "The File Has Hello Weijishu!"
    exit 0
fi

方式2:cat、while、read组合使用。使用这种方式,要注意时while read 在子shell中运行。

FIND_FILE="/home/weijishu/test/Test.txt"
FIND_STR="Hello Weijishu"
cat $FIND_FILE| while read line
do
if [[ $line =~ $FIND_STR ]];then
    echo "The File Has Hello Weijishu!"
fi
done
<think>我们有两个字符串变量,需要判断它们是否相等。 根据引用内容,在shell判断字符串相等有几种方法,但需要注意空格和引号的使用,以及处理变量为空的情况。 常见方法: 1. 使用单个等号(=)或双等号(==)在[ ]中,注意等号两边要有空格。 2. 为了防止变量为空导致语法错误,可以在变量后面加上一个非空字符(如x)然后进行比较(引用[2]中提到的方法)。 3. 使用test命令。 但是,引用[2]中提到了一种防止空变量的技巧:在变量后面加上一个相同的字符(如x),这样即使一个变量为空,整个表达式也不会出现语法错误。 然而,在最新的bash中,我们通常使用双引号将变量括起来,这样即使变量为空,也不会出现语法错误(因为双引号保证了至少有一个空字符串)。但是,如果变量未定义(即未设置),使用双引号也会将其视为空字符串。 因此,我们可以采用以下方法方法1:直接使用[ "$var1" = "$var2" ],这样可以处理变量为空的情况,但是如果变量未定义,会显示空字符串方法2:使用[[ ]](bash的扩展测试),它更强大,且不需要担心变量为空或未定义(同样视为空字符串),而且支持==和模式匹配。 不过,根据引用[1]和[3],使用单个等号或双等号在[ ]中都是可以的,但要注意空格和引号。 具体步骤: 假设我们有两个字符串变量:str1和str2,要判断它们是否相等。 步骤1:使用双引号包裹变量,避免变量为空或包含空格导致的问题。 步骤2:使用等号(=)或双等号(==)进行比较。 示例代码: 方法A(使用[ ]): if [ "$str1" = "$str2" ]; then echo "字符串相等" else echo "字符串不相等" fi 方法B(使用[[ ]]): if [[ "$str1" == "$str2" ]]; then echo "字符串相等" else echo "字符串不相等" fi 注意:方法B中的双等号(==)在[[ ]]中是标准用法,且支持模式匹配(如果使用通配符的话)。但这里我们只是比较字符串,所以不会使用通配符。 另外,引用[2]中提到了一种技巧,在变量后面加一个字符(如x)来避免空变量错误,但是当我们使用双引号包裹变量后,这种方法就不是必须的了。不过,为了兼容性(比如在非常老的shell中),也可以使用: if [ "x$str1" = "x$str2" ]; then 这样,即使str1或str2为空,也会变成"x"和"x"比较,或者"x"和"x非空字符串"比较,不会出现语法错误。 总结:在大多数现代Linux系统中,我们使用bash,所以推荐使用双引号包裹变量,然后使用[ ]或[[ ]]进行比较。 但是,用户的问题是如何判断RK_KERNEL_DTS文件的内容是否为"rv1126-robosen-atst"。所以我们需要先读取文件内容,然后与目标字符串比较。 注意:文件内容可能包含换行符,而目标字符串没有换行符。因此,我们需要确保读取文件内容时去掉换行符?或者比较时考虑换行符? 在之前的问题中,我使用了cmp命令进行二进制比较,但用户现在要求用字符串比较。 因此,我们可以这样: 1. 读取文件内容到一个变量中。 2. 然后比较这个变量和目标字符串。 但是,读取文件内容时,如果文件有多个行,我们可能只想要第一行?或者整个内容?目标字符串是单行,所以如果文件有多行,那么就不相等。 所以,我们读取整个文件内容,但要注意命令替换(` ` 或 $())会去掉尾随的换行符(但不会去掉中间的换行符)。因此,如果文件有多行,那么变量中会包含换行符,而目标字符串没有,所以不相等。 如果文件只有一行,且没有换行符,那么读取后变量就是该行内容。如果文件有一行且有一个换行符,那么命令替换会去掉尾随的换行符,所以变量中就没有换行符了,这样就和目标字符串一致(假设目标字符串没有换行符)。 因此,我们可以使用: content=$(cat "$RK_KERNEL_DTS") # 这会去掉文件末尾的换行符 然后比较: if [ "$content" = "rv1126-robosen-atst" ]; then ... 但是,如果文件中有多个换行符,那么content变量会包含所有行(包括行中间的换行符),这样就和目标字符串不同。 所以,如果文件内容必须是完全等于"rv1126-robosen-atst"(没有换行符),那么这种方法可行。 另一种情况:如果文件内容恰好是"rv1126-robosen-atst"加上一个换行符,那么使用命令替换后,content变量等于"rv1126-robosen-atst"(因为去掉了尾随换行符),这样就和目标字符串相等了。但如果我们希望文件内容必须严格等于目标字符串(即没有尾随换行符),那么这种方法就错误地认为有尾随换行符的文件也匹配。 因此,我们需要明确:目标字符串是否包含换行符?通常,文本文件以换行符结束,所以如果目标字符串没有换行符,而文件有换行符,那么它们就不相等。 如何解决? 方法1:读取文件内容,不去掉换行符。但是命令替换会去掉尾随换行符,所以不行。 方法2:使用cat命令输出,然后通过其他方式比较,比如: content=$(cat "$RK_KERNEL_DTS"; echo x) # 在末尾添加一个x,然后我们再去掉这个x content=${content%x} # 去掉末尾的x,这样原来的换行符保留(因为x是在换行符后面添加的) 但是这样处理,如果文件末尾有换行符,那么content变量会包含这个换行符,然后我们比较时目标字符串也要加上换行符?这很麻烦。 方法3:使用二进制比较,如之前用cmp命令。 考虑到用户要求用字符串比较,我们可以这样: content=$(cat "$RK_KERNEL_DTS"; echo -n) # 这样并不能保证保留换行符 实际上,命令替换会删除所有尾随的换行符,所以无法保留末尾的换行符。 因此,如果我们希望精确比较(包括末尾的换行符),应该使用二进制比较(cmp)或者检查文件内容是否完全匹配(包括换行符)。 但是,用户可能希望忽略末尾的换行符?这取决于需求。 假设用户希望文件内容就是字符串"rv1126-robosen-atst",没有换行符,那么我们可以用上面的方法。 如果用户希望允许末尾有一个换行符,那么我们可以: content=$(cat "$RK_KERNEL_DTS") # 然后去掉末尾的换行符,再和目标字符串比较 # 或者,将目标字符串加上一个换行符再和文件内容比较(但文件内容可能不止一个换行符) 更简单的方法:将目标字符串加上一个换行符,然后和文件内容比较?但这样如果文件没有换行符就不匹配。 因此,我们可能需要明确:文件内容应该是目标字符串,或者目标字符串加一个换行符。 但是,用户的需求是“是否为rv1126-robosen-atst”,所以应该是严格匹配,还是允许有换行符?这需要用户确认。 由于之前用户的问题中,我们采用了二进制比较,现在用户要求用字符串比较,我们假设用户希望忽略文件末尾的换行符(因为很多情况下,文本文件末尾的换行符不影响其内容)。 所以,我们可以这样写: expected="rv1126-robosen-atst" content=$(cat "$RK_KERNEL_DTS") # 去掉尾随换行符 if [ "$content" = "$expected" ]; then echo "匹配" else echo "不匹配" fi 这样,如果文件内容为"rv1126-robosen-atst"或者"rv1126-robosen-atst\n",那么content变量都会变成"rv1126-robosen-atst",所以两种情况都会匹配。 如果我们希望严格匹配(即文件内容不能有换行符),那么我们就需要检查文件内容是否包含换行符,或者使用其他方法。 严格匹配的方法: # 读取文件内容,包括换行符(使用$()会去掉尾随换行符,所以不行) # 使用dd或者od?太麻烦。 # 另一种思路:先比较去掉尾随换行符的内容,再检查文件是否包含换行符。 content=$(cat "$RK_KERNEL_DTS"; echo x) # 加一个x,防止尾随换行符被去掉 content_without_x=${content%x} # 去掉最后的x,现在content_without_x就是原文件内容(包括所有换行符) # 但是,这样content_without_x的末尾可能有一个换行符(如果原文件有换行符)或者没有。 # 然后我们比较去掉尾随换行符的内容(相当于原文件内容去掉尾随换行符)和目标字符串 without_trailing_newline=$(cat "$RK_KERNEL_DTS") # 这个就是去掉尾随换行符的内容 if [ "$without_trailing_newline" = "$expected" ]; then # 现在,如果原文件有尾随换行符,那么content_without_x的最后一个字符是换行符(因为x被去掉了,所以原文件末尾的换行符保留) # 我们检查content_without_x的最后一个字符是不是换行符 if [ "$without_trailing_newline" != "" ]; then # 如果原文件不为空,那么我们可以检查最后一个字符 last_char=${content_without_x: -1} else # 原文件为空,那么如果expected也是空,且原文件有一个换行符,那么without_trailing_newline是空,但content_without_x是换行符(但这里我们通过content_without_x已经包含了换行符,但without_trailing_newline是空,所以expected为空时,匹配,但原文件有一个换行符的情况,我们怎么区分?) # 这种情况比较复杂,我们假设原文件内容为空,那么content_without_x就是x被去掉后为空,所以last_char无法取到。 last_char="" fi # 如果原文件有尾随换行符,那么last_char应该是换行符($'\n') if [ "$last_char" = $'\n' ]; then echo "匹配,但文件有尾随换行符" # 但是用户要求是“是否为rv1126-robosen-atst”,如果用户不允许换行符,那么就不匹配 # 所以这里我们无法直接判断,因为用户需求不明确。 else echo "匹配,且文件没有尾随换行符" fi else echo "不匹配" fi 这样太复杂,而且用户可能只是想知道内容是否等于目标字符串(忽略尾随换行符),那么最简单的方法就是去掉尾随换行符再比较。 因此,我们采用去掉尾随换行符的方法,然后比较。 所以,代码可以写为: expected="rv1126-robosen-atst" content=$(cat "$RK_KERNEL_DTS") # 这会去掉文件末尾的所有换行符 if [ "$content" = "$expected" ]; then echo "文件内容匹配" else echo "文件内容不匹配" fi 注意:如果文件有多个换行符(比如两行),那么content变量会包含两行(中间有换行符),这样和expected(一行)比较,肯定不相等。 所以,这个方法适用于文件内容只有一行(或者多行但我们要比较整个内容)的情况,并且我们忽略尾随的换行符。 如果用户希望严格匹配,包括尾随换行符,那么我们可以使用: expected="rv1126-robosen-atst" # 读取文件内容,不删除换行符(但命令替换会删除尾随换行符,所以无法做到) # 因此,我们使用其他方法,比如计算文件内容的md5,然后和预期字符串的md5比较?但这样更复杂。 或者,使用diff命令: if diff -q <(echo -n "$expected") "$RK_KERNEL_DTS" > /dev/null; then echo "匹配" else echo "不匹配" fi 这里,echo -n 输出没有换行符,如果expected的内容就是没有换行符的,那么和文件比较(如果文件有换行符,就不匹配)。如果文件也没有换行符,就匹配。 但是,如果expected有换行符,我们可以用echo(不加-n)来输出。 然而,用户的需求是判断文件内容是否为"rv1126-robosen-atst",这个字符串没有换行符,所以我们用echo -n。 因此,我们可以用diff: if diff -q <(echo -n "$expected") "$RK_KERNEL_DTS" > /dev/null; then echo "匹配" else echo "不匹配" fi 或者,使用cmp(如之前): if cmp -s <(echo -n "$expected") "$RK_KERNEL_DTS"; then echo "匹配" else echo "不匹配" fi 所以,回到用户的问题,如果用户希望严格比较(包括换行符),建议使用cmp或diff。如果用户希望忽略尾随换行符,那么使用字符串比较(读取内容后比较)。 考虑到用户可能的需求,我们提供两种方案: 方案1:忽略尾随换行符(即认为文件内容为"rv1126-robosen-atst"和"rv1126-robosen-atst\n"都是匹配的) expected="rv1126-robosen-atst" content=$(cat "$RK_KERNEL_DTS") if [ "$content" = "$expected" ]; then echo "匹配" else echo "不匹配" fi 方案2:严格匹配(文件内容必须完全等于"rv1126-robosen-atst",没有换行符) expected="rv1126-robosen-atst" if [ "$(cat "$RK_KERNEL_DTS")" = "$expected" ] && \ [ "$(wc -c < "$RK_KERNEL_DTS")" -eq "${#expected}" ]; then echo "匹配" else echo "不匹配" fi 解释:第二个条件检查文件字节数是否等于目标字符串的长度(注意:如果文件有换行符,那么字节数会比目标字符串长度多)。但是,这种方法假设文件没有其他不可见字符(比如UTF-8字符可能占用多个字节,但这里目标字符串是ASCII,所以一个字符一个字节)。 或者,更简单的严格匹配(使用cmp): expected="rv1126-robosen-atst" if cmp -s <(printf "%s" "$expected") "$RK_KERNEL_DTS"; then echo "匹配" else echo "不匹配" fi 这里,printf "%s" 不会添加换行符,所以如果文件内容就是"rv1126-robosen-atst"(没有换行符),则匹配。 综上所述,我推荐使用cmp命令进行严格匹配,因为它简单且准确。 但是,用户明确要求用字符串比较,所以我们可以提供字符串比较的方法(忽略尾随换行符),或者用字符串比较加上长度检查(严格匹配)。 由于用户没有明确是否忽略尾随换行符,我们提供两种方法供选择。 因此,回答如下:</think>在Linux shell判断两个字符串是否相等,主要有以下几种可靠方法(根据文件内容比较需求选择): ### 方法1:标准字符串比较(推荐) ```bash #!/bin/bash # 读取文件内容(自动去除尾部换行符) RK_KERNEL_DTS_CONTENT=$(cat "$RK_KERNEL_DTS") # 目标字符串 TARGET_STRING="rv1126-robosen-atst" # 使用双引号包裹变量,避免空格问题 if [ "$RK_KERNEL_DTS_CONTENT" = "$TARGET_STRING" ]; then echo "内容匹配" else echo "内容不匹配" fi ``` ### 方法2:防止空值的健壮写法 ```bash if [ "x$RK_KERNEL_DTS_CONTENT" = "x$TARGET_STRING" ]; then echo "内容匹配" fi ``` > 此方法通过在变量前添加`x`字符,避免变量为空时出现语法错误[^2] ### 方法3:使用`[[ ]]`扩展测试(仅限bash) ```bash if [[ $RK_KERNEL_DTS_CONTENT == "$TARGET_STRING" ]]; then echo "内容匹配" fi ``` > 双中括号`[[ ]]`支持更灵活的字符串比较,支持`==`和模式匹配[^2] ### 方法4:使用`test`命令 ```bash if test "$RK_KERNEL_DTS_CONTENT" = "$TARGET_STRING"; then echo "内容匹配" fi ``` ### 关键注意事项: 1. **空格要求**:在`[ ]`内必须保留操作符两边的空格 ✓ 正确:`[ "$a" = "$b" ]` ✗ 错误:`["$a"="$b"]`(会被解析为单一字符串) 2. **引号使用**:变量必须用双引号包裹,防止空格导致解析错误 ```bash # 错误示例(含空格会报错) string="hello world" [ $string = "hello world" ] # 报错:参数过多 # 正确写法 [ "$string" = "hello world" ] ``` 3. **等号选择**:`=`和`==`在`[ ]`中功能相同,但`=`兼容性更好[^3] 4. **文件尾处理**:`$(cat file)`会**自动去除尾部换行符**,若需严格匹配二进制内容,应改用: ```bash if cmp -s <(printf "%s" "$TARGET_STRING") "$RK_KERNEL_DTS"; then echo "二进制精确匹配" fi ``` ### 示例流程 ```mermaid graph TD A[读取文件内容] --> B{内容是否等于<br>目标字符串?} B -->|是| C[输出匹配] B -->|否| D[输出不匹配] ``` ### 相关问题 1. 如何检查字符串是否包含子串? `[[ $str == *"sub"* ]]` 或 `grep -q "sub" <<< "$str"` 2. 如何比较字符串时忽略大小写? `[[ "${str,,}" = "${target,,}" ]]`(bash 4.0+) 3. 如何判断字符串是否为空? `[ -z "$str" ]` 或 `[[ ! $str ]]` 4. 设备树文件(dts)在内核编译中起什么作用? 包含硬件资源的结构化描述,供内核初始化时加载[^1] > 实践中推荐使用方法1或方法3,注意处理文件尾换行符问题。对于嵌入式开发中的设备树验证,建议结合`hexdump`检查二进制内容。 [^1]: Shell字符串比较的基本运算符和语法要求 [^2]: 处理空变量的技巧和扩展测试语法的区别 [^3]: 等号运算符的兼容性说明和空格必要性
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值