Как получить символ в заданной позиции строки в сценарии оболочки?

22

Как получить символ в заданной позиции строки в сценарии оболочки?

Том Брито
источник

Ответы:

36

В bash с «Расширением параметра» $ {параметр: смещение: длина}

$ var=abcdef
$ echo ${var:0:1}
a
$ echo ${var:3:1}
d

Изменить: без расширения параметров (не очень элегантно, но это то, что пришло ко мне в первую очередь)

$ charpos() { pos=$1;shift; echo "$@"|sed 's/^.\{'$pos'\}\(.\).*$/\1/';}
$ charpos 8 what ever here
r
forcefsck
источник
1
gnu.org/software/bash/manual/… имеет больше деталей
jsbillings
Очевидно, не POSIX: pubs.opengroup.org/onlinepubs/009695399/utilities/…
Сиро Сантилли 新疆 新疆 中心 法轮功 六四 事件
Вы также можете установить смещение «от конца» примерно такecho ${var: -2:1}
Vassilis
Этот синтаксис взят из ksh93 и также поддерживается zshи mksh.
Стефан
6

Альтернатива расширению параметра expr substr

substr STRING POS LENGTH
    substring of STRING, POS counted from 1

Например:

$ expr substr hello 2 1
e
кендырь
источник
круто, надо было проверять expr более тщательно.
forcefsck
1
Хотя это похоже на работу с выражением из GNU coreutils, substrоно не включено в выражение из FreeBSD, NetBSD или OS X. Это не переносимое решение.
Ghoti
@ ghoti, обратите внимание, что substrизначально это не расширение GNU. Первоначальная реализация exprпришла из PWB Unix в конце 70-х и имела substr(но не :).
Стефан
@ StéphaneChazelas, спасибо за добавление исторической перспективы. :) Хотя я почти уверен, что использование PWB не имеет отношения к OP, всегда интересно отслеживать функции и изменения в течение десятилетий. GNU, как правило, используется многими людьми по умолчанию, но в целом, я думаю, что я бы избегал использования опций, которые явно не относятся к POSIX и, как известно, отсутствуют в основных единицах.
Ghoti
5

cut -c

Если переменная не содержит символов новой строки, вы можете сделать:

myvar='abc'
printf '%s\n' "$myvar" | cut -c2

выходы:

b

awk substr это еще одна альтернатива POSIX, которая работает, даже если переменная имеет символы новой строки:

myvar="$(printf 'a\nb\n')" # note that the last newline is stripped by
                           # the command substitution
awk -- 'BEGIN {print substr (ARGV[1], 3, 1)}' "$myvar"

выходы:

b

printf '%s\n'чтобы избежать проблем с escape-символами: /programming//a/40423558/895245 например:

myvar='\n'
printf '%s\n' "$myvar" | cut -c1

выходы \как положено.

Смотрите также: /programming/1405611/extracting-first-two-characters-of-a-string-shell-scripting

Проверено в Ubuntu 19.04.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
источник
printf '%s' "$myvar" | cut -c2не POSIX, так как вывод printfне является текстом, если не $myvarзаканчивается символом новой строки. В противном случае предполагается, что переменная не содержит символов новой строки, так как cutобрезает каждую строку ввода.
Стефан
Тот awkбыл бы более эффективным и надежным сawk -- 'BEGIN {print substr (ARGV[1], 2, 1)}' "$myvar"
Стефан
Обратите внимание, что в текущих версиях GNU cutэто не работает для многобайтовых символов (то же самое для mawk или busybox awk)
Стефан
@ StéphaneChazelas спасибо за очки. Я не понял, что вы имеете в виду в первом: вы имеете в виду, что printf 'abc '| cut -c2это неправильно, потому что нет \n(об этом я не знаю), или что команда не выполнится, если у myvar есть новые строки (это я согласен)?
Сиро Сантилли 新疆 事件 中 at 法轮功 六四 事件
1
Поведение cutне определено, если ввод не текстовый (хотя cutреализации требуются для обработки строк или произвольной длины). Вывод printf abcне является текстом, поскольку он не заканчивается символом новой строки. На практике, в зависимости от реализации, если вы передадите это cut -c2, вы получите либо ничего b, b<newline>либо вообще ничего. Вам нужно printf 'abc\n' | cut -c2получить поведение, указанное в POSIX (это необходимо для вывода b<newline>)
Стефан
1

С помощью zshили yashвы бы использовали:

$ text='€$*₭£'
$ printf '%s\n' "${text[3]}"
*

zsh, вы можете сократить его до printf '%s\n' $text[3]).

Стефан Шазелас
источник
0

Вы можете использовать команду вырезать. Чтобы получить 3-е положение:

echo "SAMPLETEXT" | cut -c3

Проверьте эту ссылку http://www.folkstalk.com/2012/02/cut-command-in-unix-linux-examples.html

( Расширенные случаи ) Однако, изменение IFS также является хорошей вещью, особенно когда ваш ввод может содержать пробелы. Только в этом случае используйте приведенный ниже

saveifs=$IFS
IFS=$(echo -en "\n\b")
echo "SAMPLETEXT" | cut -c3
IFS=$saveifs
Мидхун Хосе
источник
Я не вижу, как IFSв игру вступит код, который вы опубликовали.
Кусалананда