Как разбить строку в оболочке и получить последнее поле

Предположим, что у меня есть строка 1:2:3:4:5, и я хочу получить ее последнее поле (5 в этом случае). Как это сделать с помощью Bash? Я пробовал cut, но я не знаю, как указать последнее поле с -f.

Ответ 1

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

$ foo=1:2:3:4:5
$ echo ${foo##*:}
5

Это сглаживает все с фронта до жадности.:

${foo  <-- from variable foo
  ##   <-- greedy front trim
  *    <-- matches anything
  :    <-- until the last ':'
 }

Ответ 2

Другим способом является обратное до и после cut:

$ echo ab:cd:ef | rev | cut -d: -f1 | rev
ef

Это позволяет легко получить последнее, но одно поле или любой диапазон полей, пронумерованных с конца.

Ответ 3

Трудно получить последнее поле с помощью разреза, но здесь (один набор) решений в awk и perl

$ echo 1:2:3:4:5 | awk -F: '{print $NF}'
5
$ echo 1:2:3:4:5 | perl -F: -wane 'print $F[-1]'
5

Ответ 4

Предполагая довольно простое использование (например, исключение разделителя), вы можете использовать grep:

$ echo "1:2:3:4:5" | grep -oE "[^:]+$"
5

Разбивка - найдите все символы, а не разделитель ([^:]) в конце строки ($). -o выводит только соответствующую часть.

Ответ 5

Один из способов:

var1="1:2:3:4:5"
var2=${var1##*:}

Другой, используя массив:

var1="1:2:3:4:5"
saveIFS=$IFS
IFS=":"
var2=($var1)
IFS=$saveIFS
var2=${var2[@]: -1}

Еще один с массивом:

var1="1:2:3:4:5"
saveIFS=$IFS
IFS=":"
var2=($var1)
IFS=$saveIFS
count=${#var2[@]}
var2=${var2[$count-1]}

Использование Bash (version >= 3.2) регулярных выражений:

var1="1:2:3:4:5"
[[ $var1 =~ :([^:]*)$ ]]
var2=${BASH_REMATCH[1]}

Ответ 6

$ echo "a b c d e" | tr ' ' '\n' | tail -1
e

Просто переведите разделитель в новую строку и выберите последнюю запись с помощью tail -1.

Ответ 7

Использование sed:

$ echo '1:2:3:4:5' | sed 's/.*://' # => 5

$ echo '' | sed 's/.*://' # => (empty)

$ echo ':' | sed 's/.*://' # => (empty)
$ echo ':b' | sed 's/.*://' # => b
$ echo '::c' | sed 's/.*://' # => c

$ echo 'a' | sed 's/.*://' # => a
$ echo 'a:' | sed 's/.*://' # => (empty)
$ echo 'a:b' | sed 's/.*://' # => b
$ echo 'a::c' | sed 's/.*://' # => c

Ответ 9

Здесь есть много хороших ответов, но все же я хочу поделиться этим, используя базовое имя:

 basename $(echo "a:b:c:d:e" | tr ':' '/')

Однако он потерпит неудачу, если в вашей строке уже есть некоторые символы '/'. Если косая черта/является вашим разделителем, то вам просто нужно (и нужно) использовать базовое имя.

Это не лучший ответ, но он просто показывает, как вы можете быть креативными, используя команды bash.

Ответ 10

Использование Bash.

$ var1="1:2:3:4:0"
$ IFS=":"
$ set -- $var1
$ eval echo  \$${#}
0

Ответ 11

echo "a:b:c:d:e"|xargs -d : -n1|tail -1

Сначала используйте xargs, разделив его, используя ":", - n1 означает, что каждая строка имеет только одну часть. Затем pring последняя часть.

Ответ 12

Если вам нравится python и у вас есть возможность установить пакет, вы можете использовать эту утилиту python.

# install pythonp
pythonp -m pip install pythonp

echo "1:2:3:4:5" | pythonp "l.split(':')[-1]"
5

Ответ 13

for x in `echo $str | tr ";" "\n"`; do echo $x; done

Ответ 14

Для тех, кто знаком с Python, https://github.com/Russell91/pythonpy - хороший выбор для решения этой проблемы.

$ echo "a:b:c:d:e" | py -x 'x.split(":")[-1]'

Из справки по pythonpy: -x treat each row of stdin as x.

С помощью этого инструмента легко написать код Python, который будет применен к входным данным.

Ответ 15

решение с использованием встроенного чтения

IFS=':' read -a field <<< "1:2:3:4:5"
echo ${field[4]}

Ответ 16

Может быть немного поздно с ответом, хотя простое решение состоит в том, чтобы изменить порядок ввода строки. Это позволит вам всегда получать последний предмет независимо от его длины.

[[email protected] bin]$ echo 1:2:3:4:5 | rev | cut -d: -f1
5

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

[[email protected] bin]$ echo 1:2:3:4:5:8:24 | rev | cut -d: -f1
42
[[email protected] bin]$ echo 1:2:3:4:5:8:24 | rev | cut -d: -f1 | rev
24

Надеюсь, я могу помочь, ура

Ответ 17

Сопоставление регулярных выражений в sed является жадным (всегда идет к последнему вхождению), которое вы можете использовать в своих интересах здесь:

$ foo=1:2:3:4:5
$ echo ${foo} | sed "s/.*://"
5