web-dev-qa-db-ja.com

Shellで文字列を分割して最後のフィールドを取得する方法

1:2:3:4:5という文字列があり、その最後のフィールド(この場合は5)を取得したいとします。 Bashを使ってそれを行うにはどうすればいいですか?私はcutを試しましたが、-fで最後のフィールドを指定する方法がわかりません。

263
cd1

あなたは 文字列演算子 を使うことができます。

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

これは、前から ':'まですべてを貪欲に整えます。

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

別の方法はcutの前後で逆にすることです:

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

これにより、最後の1つのフィールド、または最後から番号が付けられた任意の範囲のフィールドを取得することが非常に簡単になります。

327
a3nm

Cutを使って最後のフィールドを取得するのは困難ですが、これがawkとPerlの(1セットの)解決策です。

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

かなり単純な使い方(例えば、区切り文字をエスケープしない)を想定して、grepを使うことができます。

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

内訳 - 行末($)で区切り文字([^:])以外のすべての文字を検索します。 -o一致部分のみを印刷します。

26

一方通行:

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]}
18
$ echo "a b c d e" | tr ' ' '\n' | tail -1
e

単に区切り文字を改行に変換して、最後のエントリをtail -1で選択するだけです。

9
user3133260

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
6
Rafael

ここにはたくさんの良い答えがありますが、それでもbasenameを使ってこれを共有したいと思います。

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

ただし、文字列にすでに「/」が含まれていると失敗します。スラッシュ/があなたの区切り文字であるならば、あなたはただbasenameを使わなければなりません(そしてそうすべきです)。

これは最良の答えではありませんが、bashコマンドを使用してクリエイティブになる方法を示しているだけです。

4
021

最後のフィールドが1文字の場合は、次のようにします。

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

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

Bashの 文字列操作 を確認してください。

4
Ab Irato

Bashを使う.

$ var1="1:2:3:4:0"
$ IFS=":"
$ set -- $var1
$ eval echo  \$${#}
0
2
ghostdog74
echo "a:b:c:d:e"|xargs -d : -n1|tail -1

最初の使用xargsは ":"を使って分割します - n1はすべての行が1つの部分だけを持つことを意味します。そして最後の部分をpringします。

2
Crytis

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コードを書くのは簡単です。

1

Readビルトインを使用した解決策:

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

または、より一般的にするには

echo "${fields[-1]}" # prints the last item
1
baz
for x in `echo $str | tr ";" "\n"`; do echo $x; done
1
Nahid Akbar

sedでの正規表現のマッチングは貪欲です(常に最後に現れるものに行きます)。ここであなたが有利に使うことができます:

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

あなたがpythonが好きでパッケージをインストールするオプションがあるなら、あなたは このpythonユーティリティ を使うことができます。

# install pythonp
pythonp -m pip install pythonp

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

簡単な解決策は入力文字列の順序を逆にすることですが、答えが少し遅くなるかもしれません。これにより、長さに関係なく常に最後のアイテムを獲得できます。

[chris@desktop bin]$ echo 1:2:3:4:5 | rev | cut -d: -f1
5

ただし、この方法を使用していて、数字が1桁よりも大きい(またはどのような状況でも1文字よりも大きい)場合は、パイプ出力に対して別の 'rev'コマンドを実行する必要があります。

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

応援できたらと嬉しい

0
Chris