Я нашел здесь, как извлечь подстроку в bash, но не знаю, как применить это после канала. Например:

some func | echo ${string:12:5}

Как назначить вывод some func переменной string?

2
Michael Hays 11 Май 2018 в 18:38

3 ответа

Лучший ответ

${string:offset:length} — это оператор расширения параметра, который расширяется до диапазона символов в переменной $string.

Чтобы получить диапазон байтов из ввода (и это также будет применяться к однобайтовым символам), вы можете использовать:

func | tail -c +12 | head -c 5

Чтобы получить 5 байтов, начиная с 12-го (смещения на основе 1). Параметр -c для head не является стандартным, но довольно распространенным.

Обратите внимание, что func может быть уничтожен через некоторое время после вывода своего 16-го байта, поскольку head завершит работу после вывода этих 5 байтов, а tail будет уничтожен, если попытается записать больше данных. после этого, что будет пульсировать до func.

Вы также можете:

func | dd bs=1 skip=11 count=5 2> /dev/null

2> /dev/null позволяет избежать сообщения о состоянии в конце. Тем не менее, это подавляет все ошибки. С GNU dd вы можете заменить его на status=none, чтобы только скрыть статус.

Для больших значений length это было бы менее эффективно, поскольку за раз считывается один байт. Снова с GNU dd вы можете избежать этого, выполнив:

func | dd iflag=count_bytes,skip_bytes,fullblock skip=11 bs=64k count=5M status=none

Что будет делать столько чтений до 64 КБ каждое, чтобы получить 5 МБ байтов данных.

Теперь, когда смещение и длина должны быть выражены в символах (одно- или многобайтовых) вместо байтов, это становится более сложным.

Можно сохранить весь вывод в переменной и использовать оператор ${var:offset:length} как показано другими. Хотя это означает сохранение всего вывода в памяти. Использование var=$(func) также означает, что конечные символы новой строки отбрасываются.

Другой вариант — использовать функцию read -N bash, которая считывает заданное количество символов:

func | {
  IFS= read -rN 11 discarded
  IFS= read -rN 5 data
  printf '%s\n' "$data"
}

Или с perl (немного более эффективно для больших данных):

func | perl -Mopen=locale -sne '
  BEGIN{$total = $o + $n; $/ = \$total}
  print substr($_, $o); exit' -- -o=10000 -n=5000000
4
Stéphane Chazelas 13 Май 2018 в 01:04
string="$(func)"
echo "${string:12:5}"
2
DopeGhoti 11 Май 2018 в 18:44

Ответ

Если вы хотите извлечь вывод только из some_func, вам не нужно сохранять его в переменной, вы можете просто отправить вывод в cut, который извлечет запрошенные символы:

some_func | cut -c 12-16  

Объяснение

cut Возьмет stdin и извлечет запрошенный диапазон на основе указанных параметров.

-c Означает, что диапазон указан в символах.

12-16 Диапазон, в котором символы начинаются с индекса 1, а не 0.
Следовательно, это займет символы в позиции 12, 13, 14, 15 и 16.

Поскольку Stéphane Chazelas остался со мной, обратите внимание, что это будет работать для каждой строки ввода, а не только первая строчка.

4
Iskustvo 12 Май 2018 в 01:40
1
Обратите внимание, что он дает символы с 12-го по 16-й (байты с некоторой реализацией) каждой строки ввода, а не ввода в целом.
 – 
Stéphane Chazelas
11 Май 2018 в 19:31
Да, вы правы, может быть, я должен был отметить это с самого начала. Я обновлю ответ.
 – 
Iskustvo
12 Май 2018 в 01:37