Как сопоставить точную строку в строке между кавычками - PullRequest
0 голосов
/ 07 февраля 2019

У меня есть переменная, которая содержит, например, ['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 голосов
/ 07 февраля 2019

Есть несколько проблем с совпадением регулярного выражения в первом примере кода Bash в вопросе.Самая большая проблема заключается в том, что $search и $arr находятся на неправильных сторонах оператора матча.Отсутствие (цитируемых) одинарных кавычек в шаблоне также является серьезной проблемой.В любом случае совпадение с регулярным выражением излишне.Достаточно более простого сопоставления с шаблоном.Попробуйте это:

#!/bin/bash

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

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

См. glob - Вики Грега для получения информации о шаблонах глобуса.

0 голосов
/ 08 февраля 2019

Если вы не хотите использовать ничего, кроме bash, вы можете использовать массивы bash.

Как всегда, есть свои плюсы и минусы.Одним из преимуществ является то, что вам не нужно устанавливать какую-либо третью программу, чтобы она работала, и она будет работать и в других оболочках, таких как cygwin.

Я написал фрагмент кода, например:

#!/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"

Этот код в любом случае принимает как нечто само собой разумеющееся и имеет некоторые недостатки.

Например, считается само собой разумеющимся, что все ваши входные данные похожи на образец, без "," внутрифактические переменные.

0 голосов
/ 07 февраля 2019

С рубиновой однострочностью:

$ 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/),, поэтому я использую подстановку параметров оболочки для преобразования одинарных кавычек в двойные кавычки.

0 голосов
/ 07 февраля 2019

Некоторые ответы о том, как это сделать, на другом языке.Я думаю, вы хотите знать, почему ваш bash-скрипт не работает.

Основная причина в том, что когда вы устанавливаете check=1 внутри оператора if, вы находитесь в другой оболочке, поэтому он не 't влияет на check, который определен во внешнем скрипте.Это другая оболочка, потому что вы вводите данные в другое время из другой команды.

Несколько способов сделать эту работу:

Отправить вывод конвейера grep во временный файл, затем выполните цикл 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 и проверьте код выхода.

0 голосов
/ 07 февраля 2019

Я нашел способ изменить глобальную переменную в цикле.Спасибо всем за предложение.Вот сценарий:

#!/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
0 голосов
/ 07 февраля 2019

Как уже говорили другие, используйте jq для анализа JSON в bash.

Если вы действительно этого не хотите, вы можете попробовать любой из них:

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
0 голосов
/ 07 февраля 2019

В Python:

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

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

Как однострочный в сценарии оболочки, который выводит True или False:

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

Как однострочный вСценарий оболочки, который возвращает 0 (нормально) или -1 (не хорошо) состояние выхода, как обычно в оболочке:

python -c 'import sys; import ast; sys.exit(0 if sys.argv[1] in ast.literal_eval(sys.argv[2]) else -1)' "$search" "$arr"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...