Як витягнути перші два символи рядка в сценарії оболонок?


123

Наприклад, наведено:

USCAGoleta9311734.5021-120.1287855805

Я хочу витягти просто:

US

6
Дякую всім. Я в кінцевому підсумку використовував 'cut -c1-2', якщо чесно, я навіть не знав, що 'cut' є. Я хотів би сказати, що я досить досвідчений в командному рядку - але, мабуть, мені є чому навчитися.
Грег

1
@Greg, просто пам’ятайте, що вирізання виконується як окремий процес - він буде повільнішим, ніж внутрішній баш-рішення, яке я розмістив разом із ним у своїй відповіді. Це не матиме жодних значень, якщо ви не обробляєте величезні набори даних, але вам потрібно пам’ятати про це.
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не впевнені.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 新疆 改造 中心 996ICU 六四 事件, використовуючи printf, вам навіть не потрібна додаткова програма. Дивіться мою відповідь .
bschlueter

60

найпростіший спосіб

${string:position:length}

Де це витягує $lengthпідрядку з $stringat $position.

Це башти, вбудовані, тому не потрібно пробуджувати або сідати.


Це короткий, милий і найпростіший спосіб отримати підрядку.
ani627

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 /"
  • група "()" двох будь-яких символів "..", починаючи з початку рядка "^" і слідом за будь-яким символом "." повторений нуль або більше разів "*" (зворотні риски потрібні для уникнення деяких спеціальних символів)
  • за допомогою "/" вмісту першої (і єдиної в даному випадку) групи (тут зворотна косої риски - це спеціальний відхід, що відноситься до відповідного підвиразу)
  • зроблено "/"

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

8

Якщо ви знаходитесь bash, ви можете сказати:

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

Це може бути саме те, що вам потрібно ...


найпростіша і найпростіша відповідь! працював як шарм
алоха

7

Просто греп:

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

Відповідає моїм потребам. Ви можете видалити -Pваріант, щоб скоротити його. Усі регулярні вирази зрозуміють цю закономірність.
datashaman

6

Ви можете використовувати printf:

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

5

колрм - видалення стовпців з файлу

Щоб залишити перші два знаки, просто видаліть стовпці, починаючи з 3

cat file | colrm 3


2

Якщо ви хочете використовувати сценарій оболонки, а не покладатися на розширення без посівок (наприклад, так звані башизми), ви можете використовувати методи, які не потребують розщеплення зовнішніх інструментів, таких як grep, sed, cut, awk тощо, які потім зробіть ваш сценарій менш ефективним. Можливо, ефективність та переносність пози не важливі у вашому випадку використання. Але у випадку, якщо це (або як корисна звичка), ви можете скористатися наступним методом розширення параметрів, щоб витягти перші два символи змінної оболонки:

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

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

Цей метод був раніше описаний у цій відповіді на питання "Shell = Перевірте, чи починається змінна з #". Ця відповідь також описує пару подібних методів розширення параметрів, які можна використовувати в дещо іншому контексті, ніж той, який стосується тут оригінального питання.


Найкраща відповідь має бути зверху. ні вилок, ні башизмів. працює навіть з невеликими оболонками, такими як тире.
термін

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;

посилання: субстр


1
враховуючи, що він / вона, ймовірно, називає це з оболонки, кращою формою будеperl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'
Chas. Оуенс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.