Як отримати останній символ рядка в оболонці?


125

Я написав наступні рядки, щоб отримати останній символ рядка:

str=$1
i=$((${#str}-1))
echo ${str:$i:1}

Він працює для abcd/:

$ bash last_ch.sh abcd/
/

Це не працює дляabcd* :

$ bash last_ch.sh abcd*
array.sh assign.sh date.sh dict.sh full_path.sh last_ch.sh

У ньому перераховані файли в поточній папці .

Відповіді:


96

Ось одна з причин, чому потрібно цитувати свої змінні:

echo "${str:$i:1}"

В іншому випадку bash розширює змінну і в цьому випадку робить глобалізацію перед друком. Також краще навести параметр до сценарію (якщо у вас є відповідне ім'я файлу):

sh lash_ch.sh 'abcde*'

Також див. Порядок розширень у посібнику з bash . Змінні розгортаються перед розширенням імені файлу.

Для отримання останнього символу слід просто використовувати -1як індекс, оскільки від'ємні індекси рахуються з кінця рядка:

echo "${str: -1}"

Простір після двокрапки ( :) ПОТРІБНО.

Цей підхід не буде працювати без місця.


62
До речі, від’ємні показники рахуються справа, так "${1: -1}"достатньо.
choroba

7
Ви повинні відповісти як формальне рішення, а не тут, у коментарях.
BMW

FYI: Ви також можете це зробити в "одноколірному", як echo "${str:$((${#str}-1)):1}". Це дозволяє змінювати також повернуті символи, що повертаються. Ця робота для мене в bash v4.1.0 (1)
SaxDaddy,

16
@ choroba відповідь: Зверніть увагу на прокляте місце! Це завжди мене "${1:-1}
відвертає

192

Перші @perreal, цитування змінних важливо, але тому, що я читав цю публікацію як 5 разів, перш ніж знайти в коментарях простіший підхід до питання ...

str='abcd/'
echo "${str: -1}"

Вихід: /

str='abcd*'
echo "${str: -1}"

Вихід: *

Дякуємо всім, хто брав участь у цьому вище; Я належним чином додав +1 у всій нитці!


25
Примітка: відзначте простір всередині ${std: -1}, без місця це не спрацює. Я наткнувся на це і виявив, що ${std:~0}також працює (з простором або без місця). Не впевнений, чи є це документально підтверджене поведінка, я не намагався це шукати.
Барт

4
це задокументовано. man bash каже: Арифметичні вирази, що починаються з -, повинні бути відокремлені пробілом від попереднього: відрізнятись від розширення Використовувати значення за замовчуванням
mighq

3
Це приголомшливо, дякую за обмін. Сторінка BASH майже непосильна для читання, хоча я там бував кілька разів. Я думаю, що вони могли б пройти курс коледжу навколо сценаріїв оболонок лол
quickshiftin

3
Це рішення не працює в .shсценарії при спробі призначити отриманий символ змінній. Наприклад, declare LAST=$(echo "${str: -1}") це призведе до неприємної червоної смуги, яка показує синтаксичну помилку, починаючи з:
krb686

3
якщо перевірка синтаксису редактора не любить цей пробіл, спробуйте${str:0-1}
ttt

36

Я знаю, що це дуже стара тема, але ніхто не згадав, яка для мене найчистіша відповідь:

echo -n $str | tail -c 1

Зауважте, -nце просто так, що ехо не включає в себе новий рядок в кінці.


15
Навіть не є чистішим, ніж $ {str: -1}
майстриня

8
Він чистіший, оскільки не покладається на башмаку, тому він буде працювати з будь-якою оболонкою Posix.
Джон Ейкенберрі

Що найбільше "башист"? "$ {str: -1}" І ... Що найчистіше? "$ {str: -1}" Баш - це беш! :-)
Роджер

Для тих, хто намагається надрукувати останні символи у великому файлі, це зробило для мене роботу: cat user / folder / file.json | Хвіст -c 1 Ви можете замінити 1 на кількість символів, які потрібно надрукувати.
Дієго Серрано

5

інше рішення за допомогою сценарію awk:

останні 1 знак:

echo $str | awk '{print substr($0,length,1)}'

останні 5 символів:

echo $str | awk '{print substr($0,length-5,5)}'

1
Не те, що просила ОП, але це найкраще рішення, яке я використовував з файлом. Більшість інших підходів не спрацює з кодом файлу до нього, як у: cat file | awk '{print substr($0,length,1)}'Спасибі!
xmar

4

Одина рядок:

${str:${#str}-1:1}

Зараз:

echo "${str:${#str}-1:1}"

1
Чому ви використовуєте дві пари в дужках? Також, починаючи з 4.2, ви можете використовувати негативні компенсації, як показано у відповіді на швидку зміну: echo "${str: -1}"достатньо (пам’ятайте пробіл між :і -).
gniourf_gniourf

Дві пари круглих дужок використовуються для арифметичних операцій
Едуардо Куомо

Ні. Перегляньте відповідну частину посібника, де ви читаєте: довжина та зміщення - це арифметичні вирази (див. Арифметику оболонки ); значить, ви вже в арифметиці оболонки і зовсім не потребуєте дужок. Крім того, якщо то , що ви сказали , були правдою, це було б більш логічно було б мати арифметичне розширення з $((...)).
gniourf_gniourf

@gniourf_gniourf ви праві! Зараз я розумію ваше попереднє запитання. Відповідь оновлено
Едуардо Куомо

4

Кожна відповідь поки що означає, що слово "оболонка" у запитанні прирівнюється до Bash.

Ось як це можна зробити в стандартній оболонці Борна:

printf $str | tail -c 1

1
echo -nяк запропоновано користувачем5394399, уникає проблем, коли $strмістить символи спеціального формату.
Конрад Мейєр

-nПеремикач є bashism. Він не працюватиме в стандартній оболонці Борна як тире і т. Д. ... Який був пункт моєї відповіді.
феп

1
Не зовсім башизм, але POSIX визнає, що це визначено реалізацією ("Якщо перший операнд - -n, або якщо будь-який з операндів містить символ <зворотний штрих>, результати визначаються реалізацією"). Натомість вашу відповідь можна зафіксувати за допомогою printf "%s" "$str" | ...:-).
Конрад Мейєр

4

Спробуйте:

"${str:$((${#str}-1)):1}"

Наприклад:

someone@mypc:~$ str="A random string*"; echo "$str"
A random string*
someone@mypc:~$ echo "${str:$((${#str}-1)):1}"
*
someone@mypc:~$ echo "${str:$((${#str}-2)):1}"
g

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.