Найти строку, зная ее часть, и вернуть строку

9

У меня есть строка, например

"Icecream123 AirplaneBCD CompanyTL1 ComputerYU1"

Допустим, я знаю, что моя строка наверняка будет содержать подстроку IceCream, но я не знаю, что за ней следует.

Это может быть 123, как в моем примере, или это может быть что-то другое.

Хотя я могу использовать grep, чтобы определить, существует ли в моей строке подстрока "Icecream", с помощью следующей команды

echo $string | grep -oF 'Icecream';

Который напечатает

Icecream

Я хочу с помощью команды, чтобы он напечатал всю подстроку, которая в моем примере

Icecream123

Конечно, то, что следует за Icecream, является случайным и неизвестно заранее, поэтому я не могу просто сделать

$SUBSTRING=$(echo $string | grep -oF 'Icecream')
$SUBSTRINGTRAIL=123
echo $SUBSTRING$SUBSTRINGTRAIL
Sonamor
источник
подстрока фиксированная / статическая - всегда "Icecream" или переменная?
Джефф Шаллер
пробел будет указывать конец желаемого суффикса?
Джефф Шаллер
@JeffSchaller К сожалению, я этого не знаю. Я на самом деле получаю многострочный вывод из другой команды, которую я сохраняю в переменной, эта переменная является моей $ string, когда она получает эхо, она отображает многострочный вывод в виде строки знака с пробелом между ними. На самом деле я не знаю, является ли это пробел или специальный символ, такой как LF. Я думал, что это космос.
Сонамор
Я имею в виду, например, Icecream123 AirplaneBCDвы хотите остановиться на 123. Это потому, что после 3 есть пробел или что-то еще?
Джефф Шаллер
1
Если вы не уверены, какие у вас данные, сложно найти подходящее решение. Все ответы до сих пор предполагают, что ваши данные в одной строке, как вы это показали. Я пытался выяснить, каков твой разделитель - где должна заканчиваться "запаздывающая" часть.
Джефф Шаллер

Ответы:

15

Если вы grepподдерживаете регулярные выражения, совместимые с perl, вы можете не жадно сопоставлять их со следующей границей слова:

echo "$string" | grep -oP 'Icecream.*?\b'

В противном случае сопоставьте самую длинную последовательность непустых символов:

echo "$string" | grep -o 'Icecream[^[:blank:]]*'

Или оставьте все в оболочке и удалите самую длинную последовательность символов, начинающуюся с пробела:

echo "${string%% *}"
steeldriver
источник
2
Для PCRE я бы использовал 'Icecream\S+'некоторые непустые символы.
Гленн Джекман
Спасибо за ваши комментарии, к сожалению, похоже, что моя версия grep не поддерживает регулярные выражения Perl. Не могли бы вы добавить более подробную информацию о вашем третьем варианте? Я не совсем уверен, как это реализовать.
Сонамор
После еще одного тестирования кажется, что с помощью echo "$ string" | grep -oP 'Icecream. *? \ b' или 'Icecream \ S +' это делает свою работу. Спасибо
Сонамор
Это действительно сбивает с толку, что хотя ваша переменная $ string является строкой, вы все равно должны поместить ее в двойные кавычки!
Сонамор
@Sonamor в этом случае цитирование не является строго необходимым; Однако существует так много случаев , когда это является , что это хорошая привычка. Смотрите, например, когда необходимо двойное цитирование?
Steeldriver
7

Используя grepчто знает о -o:

$ printf '%s\n' "$string" | grep -o '\<Icecream[^[:blank:]]*'
Icecream123

Шаблон \<Icecream[^[:blank:]]*соответствует строке Icecream(где ей Iпредшествует не состоящий из слов символ или начало строки), за которым следует ноль или более непустых пробелов (не пробелов или табуляций).


Использование awk:

$ printf '%s\n' "$string" | awk -v RS=' ' '/^Icecream/'       
Icecream123

В awkпрограмме делит строку в разделенных пробелами записи и тесты каждый один. Он напечатает те, которые начинаются со строки Icecream.

Используя mawkили GNU awk, вы также можете использовать

printf '%s\n' "$string" | awk -v RS='[[:blank:]]' '/^Icecream/'

поскольку они интерпретируются RSкак регулярное выражение, если оно содержит более одного символа.


С sed, аналогично как с grep:

$ printf '%s\n' "$string" | sed 's/.*\(\<Icecream[^[:blank:]]*\).*/\1/'
Icecream123

Использование /bin/sh:

set -- Icecream123 AirplaneBCD CompanyTL1 ComputerYU1
for string; do
    case $string in
        Icecream*)
            printf '%s\n' "$string"
            break
    esac
done

Perl (с небольшой помощью tr):

$ printf '%s\n' "$string" | tr ' ' '\n' | perl -ne '/Icecream\S*/ && print'
Icecream123

или просто

$ printf '%s\n' "$string" | perl -ne '/(Icecream\S*)/ && print $1, "\n"'
Icecream123
Кусалананда
источник
Или разделить на строки и сопоставить ключ:echo "$string" | grep -o '\S\+' | grep "Icecream"
Исаак
7

Так как вы отметили Bash:

[[ $string =~ (Icecream[^ ]*) ]] && result=${BASH_REMATCH[1]}

В более общем смысле, для условия поиска в $search:

[[ $string =~ ($search[^ ]*) ]] && result=${BASH_REMATCH[1]}

... или с расширением параметра:

# remove any leading text up to -and through- the search text:
x=${string##*$search}

# remove any trailing space onwards
result=$search${x%% *}
Джефф Шаллер
источник
2

Например, если вы используете GNU grep:

$ echo "Icecream123 AirplaneBCD CompanyTL1 ComputerYU1" | grep -oP '\bIcecream.*?(\s|$)' --color

Это использует PCRE.

Аркадиуш Драбчик
источник
1

Возможно, немного проще, особенно если учесть, что ваша версия grep не поддерживает регулярные выражения Perl:

$ echo $string | tr ' ' '\n' | grep 'Icecream' Icecream123

trРазбивает строку на строки, заменяя все пространства с символами новой строки. Тогда вы можете использовать grepлегко.

Вы также можете написать следующее, чтобы получить только то, что следует за словом, которое вы ищете:

$ echo $string | tr ' ' '\n' | sed -n 's/Icecream//p' 123

Law29
источник