Как извлечь первые два символа строки в сценарии оболочки? - PullRequest
98 голосов
/ 10 сентября 2009

Например, учитывая:

USCAGoleta9311734.5021-120.1287855805

Я хочу извлечь только:

US

Ответы [ 13 ]

153 голосов
/ 10 сентября 2009

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

pax> long="USCAGol.blah.blah.blah"
pax> short="${long:0:2}" ; echo "${short}"
US

Это установит short в качестве первых двух символов long. Если long короче двух символов, short будет идентичным ему.

Этот метод в оболочке обычно лучше, если вы собираетесь делать это много (например, 50000 раз на отчет, как вы упомянули), так как нет затрат на создание процесса. Все решения, использующие внешние программы, пострадают от этих издержек.

Если вы также хотите обеспечить минимальную длину, вы можете дополнить ее до того, как что-то вроде:

pax> long="A"
pax> tmpstr="${long}.."
pax> short="${tmpstr:0:2}" ; echo "${short}"
A.

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


Сказав это, существует множество способов сделать это с внешними программами (например, если у вас нет bash доступных для вас), некоторые из которых:

short=$(echo "${long}" | cut -c1-2)
short=$(echo "${long}" | head -c2)
short=$(echo "${long}" | awk '{print substr ($0, 0, 2)}'
short=$(echo "${long}" | sed 's/^\(..\).*/\1/')

Первые два (cut и head) идентичны для однострочной строки - они в основном оба просто возвращают вам первые два символа. Они отличаются тем, что cut даст вам первые два символа каждой строки, а head даст вам первые два символа всего ввода

Третий использует функцию подстроки awk для извлечения первых двух символов, а четвертый использует sed группы захвата (используя () и \1), чтобы захватить первые два символа и заменить все Линия с ними. Они оба похожи на cut - они доставляют первые два символа каждой строки на входе.

Ничто из этого не имеет значения, если вы уверены, что ваш ввод - одна строка, они все имеют одинаковый эффект.

40 голосов
/ 10 сентября 2009

Самый простой способ это

${string:position:length}

Где это извлекает $length подстроку из $string в $position.

Это встроенный bash, поэтому awk или sed не требуются.

31 голосов
/ 10 сентября 2009

Вы получили несколько хороших ответов, и я сам пошел бы со встроенной версией Bash, но, поскольку вы спрашивали о sed и awk и ( почти ), никто другой не предлагал решения на основе я предлагаю вам:

echo "USCAGoleta9311734.5021-120.1287855805" | awk '{print substr($0,0,2)}'

и

echo "USCAGoleta9311734.5021-120.1287855805" | sed 's/\(^..\).*/\1/'

awk должен быть довольно очевидным, но вот объяснение sed:

  • заменить "s /"
  • группа "()" из двух любых символов "..", начинающаяся в начале строки "^" и сопровождаемая любым символом "." повторяется ноль или более раз "*" (обратная косая черта необходима для экранирования некоторых специальных символов)
  • через "/" содержимое первой (и единственной, в данном случае) группы (здесь обратный слеш - это специальный escape, ссылающийся на соответствующее подвыражение)
  • сделано "/"
7 голосов
/ 02 января 2017

Просто grep:

echo 'abcdef' | grep -Po "^.."        # ab
5 голосов
/ 10 сентября 2009

Если вы в bash, вы можете сказать:

bash-3.2$ var=abcd
bash-3.2$ echo ${var:0:2}
ab

Это может быть именно то, что вам нужно ...

4 голосов
/ 19 апреля 2013

Довольно поздно, но вот оно

sed 's/.//3g'

Или

awk NF=1 FPAT=..

Или

perl -pe '$_=unpack a2'
4 голосов
/ 10 сентября 2009

colrm - удалить столбцы из файла

Чтобы оставить первые два символа, просто удалите столбцы, начиная с 3

cat file | colrm 3
1 голос
/ 13 июня 2019

Вы можете использовать printf:

$ original='USCAGoleta9311734.5021-120.1287855805'
$ printf '%-.2s' "$orginal"
US
1 голос
/ 26 марта 2018

Если вы хотите использовать сценарии оболочки и не полагаться на не-posix-расширения (такие как так называемые bashisms), вы можете использовать методы, которые не требуют разветвления внешних инструментов, таких как grep, sed, cut, awk и т. Д. , что делает ваш сценарий менее эффективным. Возможно, эффективность и переносимость posix не важны в вашем случае использования. Но в случае, если это (или просто хорошая привычка), вы можете использовать следующий параметр параметра , чтобы извлечь первые два символа переменной оболочки:

$ sh -c 'var=abcde; echo "${var%${var#??}}"'
ab

При этом используется расширение параметра "наименьший префикс" для удаления первых двух символов (это часть ${var#??}), затем расширение параметра "наименьший суффикс" (${var% part) для удаления этой строки из двух символов из исходного значения из исходного значения.

Этот метод был ранее описан в этом ответе на вопрос «Shell = Проверить, начинается ли переменная с #». В этом ответе также описывается пара похожих методов расширения параметров, которые можно использовать в несколько ином контексте, чем тот, который применяется к исходному вопросу здесь.

1 голос
/ 23 января 2017

Если ваша система использует другую оболочку (не bash), но ваша система имеет bash, тогда вы все равно можете использовать внутреннюю манипуляцию строк bash, вызывая bash с переменной:

strEcho='echo ${str:0:2}' # '${str:2}' if you want to skip the first two characters and keep the rest
bash -c "str=\"$strFull\";$strEcho;"
...