如何在引号之间的字符串中匹配确切的字符串

时间:2019-02-07 12:38:17

标签: python bash shell

我有一个变量,其中包含例如['Cars', 'House', 'Bike']。我希望能够搜索与字符串中包含的值的完全匹配。


示例:

  • 我检查变量中是否存在字符串Cars。它应该返回true
  • 我检查变量中是否存在字符串Car。它应该返回false

我尝试过的:

#!/bin/bash
search="Car"
arr="['Cars', 'House', 'Bike']"
if [[ $search =~ .*"$arr".* ]]; then
    echo "true"
else
    echo "false"
fi
# Output true | Expected false

另一个脚本:

#!/bin/bash
search="Cars"
arr="['Cars', 'House', 'Bike']"
check=0
grep -o "'[^']*'" <<<"$arr" | sed "s/'//g" |
while read -r elem; do
    if [ "$search" == "$elem" ]; then
         check=1
    fi
done
if [ "$check" == 1 ]; then
    echo "true"
else
    echo "false"
fi
# Output false | Expected true

7 个答案:

答案 0 :(得分:1)

在Python中:

search="Car"
arr="['Cars', 'House', 'Bike']"

import ast
output = search in ast.literal_eval(arr)

作为输出TrueFalse的shell脚本中的单行代码:

python -c 'import sys; import ast; print(sys.argv[1] in ast.literal_eval(sys.argv[2]))' "$search" "$arr"

作为shell脚本中的单行代码,返回0(正常)或-1(不正常)退出状态,就像在shell中一样:

python -c 'import sys; import ast; sys.exit(0 if sys.argv[1] in ast.literal_eval(sys.argv[2]) else -1)' "$search" "$arr"

答案 1 :(得分:1)

正如其他人所说,使用jq来解析bash中的JSON。

如果您真的不想这么做,可以尝试以下任何一种方法:

search="'Car'" # add the single quotes to the search string
# or
search="\bCar\b" # \b is regex syntax for word boundary, meaning the word begins/ends there

答案 2 :(得分:1)

有关使用其他某种语言执行此操作的一些答案。我想您想知道为什么您的bash脚本无法正常工作。

从根本上讲,原因是当您在if语句中设置check=1时,您所处的外壳不同,因此它不会影响外部脚本中定义的check。这是一个不同的shell,因为您正在将输入从另一个命令传递到while中。

几种可行的方法:

grep管道的输出发送到一个临时文件,然后在主shell脚本中执行while循环并从文件中读取输入。

您还可以通过退出代码返回是否找到了您要查找的字符串,并使用存储上一个进程的退出代码的check变量将其保存在$?中。

grep -o "'[^']*'" <<<"$arr" | sed "s/'//g" |
while read -r elem; do
    if [ "$search" = "$elem" ]; then
         exit 1
    fi
done 
check=$?

由于在while循环中使用退出代码基本上会使它成为fgrep的较差版本,因此您可以只使用fgrep并检查退出代码。

答案 3 :(得分:1)

问题的第一个Bash示例代码中的正则表达式匹配存在多个问题。最大的问题是$search$arr在match运算符的错误一侧。模式中缺少(双引号)单引号也是一个严重的问题。无论如何,正则表达式匹配是过大的。简单的“全局”模式匹配就足够了。试试这个:

#!/bin/bash

search=Car
arr="['Cars', 'House', 'Bike']"

if [[ $arr == *"'$search'"* ]]; then
    echo true
else
    echo false
fi

有关全局模式的信息,请参见glob - Greg's Wiki

答案 4 :(得分:0)

我找到了一种在循环中修改全局变量的方法。谢谢大家的建议。 这是脚本:

#!/bin/bash

search="Cars"
arr="['Cars', 'House', 'Bike']"
check=0
for elem in $(grep -o "'[^']*'" <<<"$arr" | sed "s/'//g")
do
    if [ "$search" == "$elem" ]; then
         check=1
    fi
done
if [ "$check" == 1 ]; then
    echo "true"
else
    echo "false"
fi
# Output true | Expected true

答案 5 :(得分:0)

使用红宝石单线:

$ json_arr="['Cars', 'House', 'Bike']"

$ ruby -rjson -e '
    data = JSON.parse(ARGV.shift)
    puts data.include?(ARGV.shift)
' "${json_arr//\'/\"}" Cars
true

$ ruby -rjson -e '
    data = JSON.parse(ARGV.shift)
    puts data.include?(ARGV.shift)
' "${json_arr//\'/\"}" Donkey
false

请注意,JSON字符串必须使用双引号(https://json.org/),因此我正在使用Shell的参数替换将单引号转换为双引号。

答案 6 :(得分:0)

如果您除了bash之外不想使用其他任何东西,可以使用bash数组。

一如既往,各有利弊。 优点之一是您无需安装任何其他程序即可使其运行,并且它也可以在其他cygwin这样的shell中运行。

例如,我写了一段代码:

#!/bin/bash
search="Car"
arr="['Cars', 'House', 'Bike']"
arr="$(printf "%s" "${arr}" | sed -e "s/,//g" -e "s/^\[/(/" -e "s/\]$/)/")"
eval arr="${arr}"
for var in ${arr[@]}; do
   if [ "${var}" = "${search}" ]; then
      printf "%s\n" "true"
      exit
   fi  
done
printf "%s\n" "false"

无论如何,这段代码都是理所当然的,并且存在一些弊端。

例如,理所当然的是,您的所有输入都像样本,实际变量中没有任何“,”。