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


123

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

USCAGoleta9311734.5021-120.1287855805

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

US

6
Спасибо всем. В итоге я использовал «cut -c1-2», честно говоря, я даже не знал, что «cut» был там. Я хотел бы сказать, что у меня довольно большой опыт работы с командной строкой, но, очевидно, мне нужно многому научиться.
Грег,

1
@Greg, просто имейте в виду, что cut запускается как отдельный процесс - он будет медленнее, чем решение internal-bash, которое я опубликовал вместе с ним в своем ответе. Это не будет иметь никакого значения, если вы не обрабатываете огромные наборы данных, но вам нужно помнить об этом.
paxdiablo

Править На самом деле, я думаю, что эта строка кода, вероятно, будет выполняться около 50 000 раз за отчет. Поэтому я мог бы просто использовать внутренний метод Bash, который, как вы сказали, сэкономит некоторые столь необходимые ресурсы.
Грег,

Ответы:


180

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

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

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

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

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

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- они доставляют первые два символа каждой строки ввода.

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


Я предпочел бы использовать printf '%s'вместо echoв случае , если есть странные символы в строке: stackoverflow.com/a/40423558/895245 Для POSIX одержит: head -cне POSIX, cut -cи awk substrэто, sed \1не уверен.
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 新疆 改造 中心 996ICU 六四 事件 используя printf, вам даже не нужна дополнительная программа. Смотрите мой ответ .
bschlueter

60

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

${string:position:length}

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

Это встроенная функция bash, поэтому использование awk или sed не требуется.


Это самый короткий, удобный и простой способ получить подстроку.
ani627 03

34

Вы получили несколько хороших ответов , и я бы с 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-код, относящийся к соответствующему подвыражению)
  • сделано "/"

1
В awk строки начинаются с индекса 1, поэтому вам следует использовать substr($0,1,2).
Исаак

8

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

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

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


самый простой и простой ответ! работал как шарм
алоха

8

Просто grep:

echo 'abcdef' | grep -Po "^.."        # ab

Подходит для моих нужд. Вы можете убрать -Pопцию, чтобы сделать его короче. Все регулярные выражения поймут этот шаблон.
datashaman

6

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

$ original='USCAGoleta9311734.5021-120.1287855805'
$ printf '%-.2s' "$original"
US

5

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

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

cat file | colrm 3


2

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

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

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

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


Лучший ответ должен быть сверху. ни вилок, ни башизмов. работает даже с небольшими оболочками, такими как тире.
exore

1

Если ваша система использует другую оболочку (не 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;"

Здесь используется тот же метод, что и в основном ответе , но вызывается только в том bashслучае, если вы его еще не использовали.
palswim

К сожалению, это связано со всеми накладными расходами, связанными с вызовом другого процесса, но иногда эти накладные расходы не так важны, как простота и знакомство.
palswim

1

Ради забавы, я добавлю несколько, которые, хотя и слишком сложны и бесполезны, но не упоминаются:

head -c 2 <( echo 'USCAGoleta9311734.5021-120.1287855805')

echo 'USCAGoleta9311734.5021-120.1287855805' | dd bs=2 count=1 status=none

sed -e 's/^\(.\{2\}\).*/\1/;' <( echo 'USCAGoleta9311734.5021-120.1287855805')

cut -c 1-2 <( echo 'USCAGoleta9311734.5021-120.1287855805')

python -c "print(r'USCAGoleta9311734.5021-120.1287855805'[0:2])"

ruby -e 'puts "USCAGoleta9311734.5021-120.1287855805"[0..1]'



0

Это то, что тебе нужно?

my $string = 'USCAGoleta9311734.5021-120.1287855805';

my $first_two_chars = substr $string, 0, 2;

ссылка: substr


1
учитывая, что он / она, вероятно, будет вызывать это из оболочки, лучшей формой будетperl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'
Chas. Owens
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.