Я хотів би видалити останній символ рядка, я спробував цей маленький сценарій:
#! /bin/sh
t="lkj"
t=${t:-2}
echo $t
але він друкує "lkj", що я роблю неправильно?
Я хотів би видалити останній символ рядка, я спробував цей маленький сценарій:
#! /bin/sh
t="lkj"
t=${t:-2}
echo $t
але він друкує "lkj", що я роблю неправильно?
Відповіді:
У оболонці POSIX синтаксис ${t:-2}
означає щось інше - він розширюється до значення, t
якщо t
встановлено і ненулеве значення, інакше до значення 2
. Щоб обрізати один символ за допомогою розширення параметра, потрібен синтаксис, який, мабуть, є${t%?}
Зверніть увагу , що в ksh93
, bash
або zsh
, ${t:(-2)}
або ${t: -2}
(зверніть увагу на пробіл) є законними як розширення підрядка , але, ймовірно , не те , що ви хочете, так як вони повертають підрядка , починаючи з позицією 2 символи в с кінця (тобто видаляє перший символ i
з рядок ijk
).
Докладнішу інформацію див. У розділі Розширення параметрів оболонки в Довідковому посібнику Bash:
${parameter%word}
видаляє найкоротший суфічний узор word
- див. розділ Розширення параметрівman bash
З bash
4.2 і вище, ви можете:
${var::-1}
Приклад:
$ a=123
$ echo "${a::-1}"
12
Зауважте, що для старих bash
(наприклад, bash 3.2.5
для ОС X) слід залишати пробіли між колонами та після них:
${var: : -1}
bash
версії 4.2-альфа і вище, занадто погана версія, до якої я маю доступ. : - /
${var:offset:lenght}
додана лише в bash 4.2
. Можливо, OSX додає свій власний патч для bash
.
для видалення останніх n
символів з рядка, в якому sed
АБО не використовується awk
:
> echo lkj | rev | cut -c (n+1)- | rev
тому, наприклад, можна видалити останній символ one character
за допомогою цього:
> echo lkj | rev | cut -c 2- | rev
> lk
з rev
manpage:
ОПИС
Утиліта rev копіює вказані файли на стандартний вихід, змінюючи порядок символів у кожному рядку. Якщо жодні файли не вказані, зчитується стандартний вхід.
ОНОВЛЕННЯ:
якщо ви не знаєте довжину рядка, спробуйте:
$ x="lkj"
$ echo "${x%?}"
lk
Використовувати sed слід так само швидко
sed 's/.$//'
Твій єдиний відгомін - це тоді echo ljk | sed 's/.$//'
.
Використовуючи це, рядок 1 рядка може бути будь-якого розміру.
Кілька варіантів залежно від оболонки:
t=${t%?}
t=`expr " $t" : ' \(.*\).'`
t=${t[1,-2]}
t=${t:0:-1}
t=${t:0:${#t}-1}
t=${t/%?}
t=${t/~(E).$/}
@ {t=$1} ~~ $t *?
Зауважте, що хоча всі повинні стягувати останній символ , ви виявите, що деякі реалізації (ті, що не підтримують багатобайтові символи) замість цього знімають останній байт (так що, швидше за все, він може пошкодити останній символ, якщо він був багатобайтовим ).
expr
Варіант передбачає $t
не закінчується в більш ніж один символ нового рядка. Він також поверне ненульовий статус виходу, якщо результуюча рядок закінчується 0
( 000
або навіть -0
з деякими реалізаціями). Він також може дати несподівані результати, якщо рядок містить недійсні символи.
t=${t%?}
це не Bourne, але ти, швидше за все, не натрапиш на шкаралупу Bourne. ${t%?}
Хоча працює у всіх інших.
fish
це незавершена робота. 2.3.0, який представив string
вбудований, не був випущений під час Q&A. З версією, на якій я її тестую, вам знадобиться string replace -r '(?s).\z' '' -- $t
(і я б очікував, що вони захочуть це змінити, вони повинні змінити прапори, які вони передають PCRE) або більш перекручені. Він також погано має справу з символами нового рядка, і я знаю, що вони також планують змінити це.
Найбільш портативна і найкоротша відповідь майже напевно:
${t%?}
Це працює в bash, sh, ash, dash, busybox / ash, zsh, ksh тощо.
Він працює за допомогою розширення параметрів оболонки Old-School. Зокрема, %
вказує на видалення найменшого суфікса параметра, t
який відповідає шаблону глобуса ?
(тобто: будь-який символ).
Дивіться "Видалення найменшого шаблону суфіксів" тут для (набагато) більш детального пояснення та додаткових відомостей. Також дивіться документи для вашої оболонки (наприклад:) у man bash
розділі "Розширення параметра".
Як бічну примітку, якщо ви хочете замість цього видалити перший символ, ви використовуєте ${t#?}
, оскільки #
збігаються з передньої частини рядка (префікса) замість задньої (суфікса).
Також варто відзначити, що обидва %
і #
мають, %%
і ##
версії, які відповідають найдовшій версії заданого шаблону замість найкоротшої. Як ${t%%?}
і ${t##?}
буде робити те ж саме , як їх одного оператора в цьому випадку, хоча (так що не додати даремний додатковий символ). Це тому, що даний ?
візерунок відповідає лише одному символу. Поєднайтеся *
з деякими недискартними картками, і речі стають цікавішими з %%
і ##
.
Розуміння розширень параметрів або, принаймні, знання про їх існування та вміння їх шукати, неймовірно корисно для написання та розшифровки сценаріїв оболонок багатьох смаків. Розширення параметрів часто виглядають як вуду-аркадна оболонка для багатьох людей, тому що ... ну ... вони є прихованою оболонкою вуду (хоча досить добре задокументовано, якщо ви знаєте шукати "розширення параметрів"). Безумовно, добре мати пояс в інструменті, коли ви застрягли в оболонці.
Ви також можете використовувати head
для друку всіх, крім останнього символу.
$ s='i am a string'
$ news=$(echo -n $s | head -c -1)
$ echo $news
i am a strin
Але, на жаль, деякі версії head
не містять провідних -
варіантів. Це стосується того, head
що поставляється з ОС X.
Це досить просто зробити, використовуючи регулярний вираз:
n=2
echo "lkj" | sed "s/\(.*\).\{$n\}/\1/"
Просто для завершення деяких можливих застосувань чистого башу:
#!/bin/bash
# Testing substring removal
STR="Exemple string with trailing whitespace "
echo "'$STR'"
echo "Removed trailing whitespace: '${STR:0:${#STR}-1}'"
echo "Removed trailing whitespace: '${STR/%\ /}'"
Перший синтаксис бере підрядку з рядка, синтаксис -
Для другого, помічайте знак, що означає "з кінця рядка", і синтаксис є
${STRING:OFFSET:LENGTH}
%
${STRING/PATTERN/SUBSTITUTION}
І ось дві коротші форми вищезгаданого
echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"
Тут знову зауважте %
знак, що означає "Видалити (тобто замінити на" ") найкоротший узор відповідного шаблону (тут представлений пробігом " \ " з кінця ПАРАМЕТРА - тут названо STR