2010-07-01 2 views

ответ

286

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

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

Это обрезает все от передней до тех пор, ':', с жадностью.

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

Хотя это работает для данной проблемы, ответ Уильяма ниже (http://stackoverflow.com/a/3163857/520162) также возвращает '5', если строка равна« 1: 2: 3: 4: 5: '(при использовании строковых операторов получается пустой результат). Это особенно удобно при анализе путей, которые могут содержать (или не) конечный символ '/'. – eckes

+7

Как бы вы тогда сделали противоположное этому? выкрикивать «1: 2: 3: 4:»? – Dobz

+8

И как сохранить деталь перед последним разделителем? По-видимому, используя '$ {foo%: *}'. '#' - с начала; '%' - от конца. '#', '%' - кратчайшее совпадение; '##', '%%' - самое длинное совпадение. –

19

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

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

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

16

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

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 (версия> = 3,2) регулярные выражения :

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

Большое спасибо за массивный стиль, поскольку мне нужна эта функция, но у меня нет разреза, awk эти утилиты. – liuyang1

3

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

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

Я бы купил некоторые подробности об этом методе, пожалуйста :-). –

+0

Может использовать 'echo $ {! #}' Вместо 'eval echo \ $$ {#}'. – Rafa

57

Это трудно получить последнее поле с помощью разреза, но здесь (один набор) решений в 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 
+5

большое преимущество этого решения над принятым ответом: оно также соответствует путям, которые содержат или не содержат финишный символ '/': '/ a/b/c/d' и'/a/b/c/d/' получить тот же результат ('d') при обработке' pwd | awk -F/'{print $ NF}' '. Принятый ответ приводит к пустому результату в случае '/ a/b/c/d /' – eckes

261

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

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

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

+11

Этот ответ хорош, потому что он использует «вырезать», который автор (предположительно) уже знаком. Кроме того, мне нравится этот ответ, потому что * I * я использую «cut» и задал этот точный вопрос, следовательно, найдя этот поток через поиск. – Dannid

+0

ха-ха - люблю его, хороший трюк! –

+6

Некоторые корма для кормления людей, использующие пробелы в качестве разделителей: 'echo '1 2 3 4" | rev | cut -d "" -f1 | rev' – funroll

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

Это приводит к проблемам, если в любом из полей есть пробел. Кроме того, он не адресует непосредственно квесты при получении поля * last *. – chepner

4

Если последнее поле является одиночный символ, вы можете сделать это:

a="1:2:3:4:5" 

echo ${a: -1} 
echo ${a:(-1)} 

Проверить string manipulation in bash.

+0

Это не работает: он дает последний _character_ 'a', а не последний _field_. –

+1

Правда, это идея, если вы знаете длину последнего поля, это хорошо. Если нет, вам нужно использовать что-то еще ... –

+0

Интересно, я не знал об этих конкретных манипуляциях с строкой Bash. Он также похож на [Строка строки/массива Python] (http://stackoverflow.com/questions/509211/explain-pythons-slice-notation). – sphakka

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

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

+0

Он не сработает, если последний элемент содержит '\ n', но для большинства случаев это наиболее читаемое решение. – Yajo

2

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

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

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

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

4

Использование 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 
2
echo "a:b:c:d:e"|xargs -d : -n1|tail -1 

Первое использование xargs разделить его с помощью ":", - n1 означает, что каждая строка только один part.Then, Принг последняя часть.

+0

Хотя это может решить проблему, всегда нужно добавить объяснение. – BDL

+0

уже добавлено .. – Crytis

0

решение с помощью чтения предопределённых

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

Для тех, кто устраивает 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, который будет применен к входу.

Смежные вопросы