Извлечь подстроку в Bash - PullRequest
613 голосов
/ 09 января 2009

Учитывая имя файла в форме someletters_12345_moreleters.ext, я хочу извлечь 5 цифр и поместить их в переменную.

Итак, чтобы подчеркнуть это, у меня есть имя файла с числом символов х, затем пятизначной последовательностью, окруженной одним подчеркиванием с обеих сторон, а затем другим набором из числа символов х. Я хочу взять пятизначное число и поместить его в переменную.

Меня очень интересует количество различных способов достижения этой цели.

Ответы [ 20 ]

10 голосов
/ 09 января 2009

Без каких-либо подпроцессов вы можете:

shopt -s extglob
front=${input%%_+([a-zA-Z]).*}
digits=${front##+([a-zA-Z])_}

Очень маленький вариант этого также будет работать в ksh93.

9 голосов
/ 06 мая 2011

Вот решение с префиксом-суффиксом (аналогично решениям, данным JB и Darron), которое соответствует первому блоку цифр и не зависит от окружающих подчеркиваний:

str='someletters_12345_morele34ters.ext'
s1="${str#"${str%%[[:digit:]]*}"}"   # strip off non-digit prefix from str
s2="${s1%%[^[:digit:]]*}"            # strip off non-digit suffix from s1
echo "$s2"                           # 12345
6 голосов
/ 21 октября 2016

Мне нравится способность sed иметь дело с группами регулярных выражений:

> var="someletters_12345_moreletters.ext"
> digits=$( echo $var | sed "s/.*_\([0-9]\+\).*/\1/p" -n )
> echo $digits
12345

Несколько более общим вариантом было бы , а не , чтобы предположить, что у вас есть подчеркивание _, обозначающее начало вашей последовательности цифр, следовательно, например, удаляя все не числа, которые вы получили до вашей последовательности: s/[^0-9]\+\([0-9]\+\).*/\1/p.


> man sed | grep s/regexp/replacement -A 2
s/regexp/replacement/
    Attempt to match regexp against the pattern space.  If successful, replace that portion matched with replacement.  The replacement may contain the special  character  &  to
    refer to that portion of the pattern space which matched, and the special escapes \1 through \9 to refer to the corresponding matching sub-expressions in the regexp.

Подробнее об этом, если вы не слишком уверены в регулярных выражениях:

  • s для _s_ubstitute
  • [0-9]+ соответствует 1+ цифрам
  • \1 ссылки на группу №1 вывода регулярного выражения (в данном случае группа 0 - это полное совпадение, группа 1 - это совпадение в скобках)
  • p флаг для _p_rinting

Все побеги \ предназначены для обработки регулярных выражений sed.

5 голосов
/ 14 августа 2016

Данный файл test.txt является файлом, содержащим «ABCDEFGHIJKLMNOPQRSTUVWXYZ»

cut -b19-20 test.txt > test1.txt # This will extract chars 19 & 20 "ST" 
while read -r; do;
> x=$REPLY
> done < test1.txt
echo $x
ST
3 голосов
/ 29 июля 2016

Мой ответ будет иметь больше контроля над тем, что вы хотите от вашей строки. Вот код того, как вы можете извлечь 12345 из вашей строки

str="someletters_12345_moreleters.ext"
str=${str#*_}
str=${str%_more*}
echo $str

Это будет более эффективно, если вы хотите извлечь что-либо, имеющее любые символы, такие как abc или любые специальные символы, такие как _ или -. Например: если ваша строка такая, и вы хотите все, что после someletters_ и до _moreleters.ext:

str="someletters_123-45-24a&13b-1_moreleters.ext"

С моим кодом вы можете указать, что именно вы хотите. Объяснение:

#* Он удалит предыдущую строку, включая соответствующий ключ. Здесь ключ, который мы упомянули, является _ % Будет удалена следующая строка, включая соответствующий ключ. Здесь ключ, который мы упомянули: «_more *»

Сделайте несколько экспериментов самостоятельно, и вы найдете это интересным.

2 голосов
/ 26 октября 2015

Хорошо, здесь идет чистая замена параметров пустой строкой. Предостережение заключается в том, что я определил someletters и moreletters как только символы. Если они буквенно-цифровые, это не будет работать, как есть.

filename=someletters_12345_moreletters.ext
substring=${filename//@(+([a-z])_|_+([a-z]).*)}
echo $substring
12345
2 голосов
/ 26 июня 2013

аналогично substr ('abcdefg', 2-1, 3) в php:

echo 'abcdefg'|tail -c +2|head -c 3
1 голос
/ 22 января 2016

Решение для bash:

IFS="_" read -r x digs x <<<'someletters_12345_moreleters.ext'

Это забьет переменную с именем x. Переменная x может быть изменена на переменную _.

input='someletters_12345_moreleters.ext'
IFS="_" read -r _ digs _ <<<"$input"
1 голос
/ 01 августа 2013

Немного поздно, но я просто наткнулся на эту проблему и обнаружил следующее:

host:/tmp$ asd=someletters_12345_moreleters.ext 
host:/tmp$ echo `expr $asd : '.*_\(.*\)_'`
12345
host:/tmp$ 

Я использовал его для получения разрешения в миллисекундах во встроенной системе, для которой нет даты% N на дату:

set `grep "now at" /proc/timer_list`
nano=$3
fraction=`expr $nano : '.*\(...\)......'`
$debug nano is $nano, fraction is $fraction
1 голос
/ 09 января 2009

Существует также команда bash buildin 'expr':

INPUT="someletters_12345_moreleters.ext"  
SUBSTRING=`expr match "$INPUT" '.*_\([[:digit:]]*\)_.*' `  
echo $SUBSTRING
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...