web-dev-qa-db-ja.com

文字列の最後の3文字のみを出力するコマンド

cutコマンドは文字列の最初のn文字を出力できることを知っていますが、最後のn文字を選択するにはどうすればよいですか?

文字数が可変の文字列がある場合、文字列の最後の3文字だけを出力するにはどうすればよいですか。例えば。

必要な「無制限」出力は「テッド」
「987654」必要な出力は「654」
「123456789」必要な出力は「789」
31
odyssey

なぜ誰も明白な答えを出していないのですか?

sed 's/.*\(...\)/\1/'

…または少しわかりにくい

grep -o '...$'

確かに、2つ目は3文字未満の行が消えてしまうという欠点があります。しかし、質問はこのケースの動作を明確に定義していませんでした。

シンプルに保つ-テール

文字を数えるためだけに、正規表現や複数のプロセスは必要ありません。
コマンドtailは、ファイルの最後のを表示するためによく使用されますが、オプション_-c_(_--bytes_)、これはこのための適切なツールのようです:

_$ printf 123456789 | tail -c 3
789
_

(シェルを使用している場合、tailのプロセスの開始を節約できるため、mikeservの回答のようなメソッドを使用することには意味があります。)

実際のUnicode文字?

次に、最後の3つを要求します文字;それはこの答えがあなたに与えるものではありません:それは最後の3つを出力しますbytes

各文字が1バイトである限り、_tail -c_が機能します。したがって、文字セットがASCII_ISO 8859-1_またはバリアントの場合に使用できます。

一般的な_UTF-8_形式のようにUnicode入力がある場合、結果は正しくありません。

_$ printf 123αβγ | tail -c 3
�γ
_

この例では、_UTF-8_を使用すると、ギリシャ文字のalpha、beta、およびgammaは2バイト長になります。

_$ printf 123αβγ | wc -c  
9
_

オプション_-m_は、少なくとも実際のUnicode文字をカウントできます。

_printf 123αβγ | wc -m
6
_

では、最後の6バイトで最後の3文字が得られます。

_$ printf 123αβγ | tail -c 6
αβγ
_

したがって、tailは一般的な文字の処理をサポートせず、試行もしません(以下を参照):可変サイズの行は処理しますが、可変サイズの文字は処理しません。

このように言いましょう:tailは、問題の構造を解決するには適切ですが、データの種類については間違っています。

GNU coreutils

さらに見ると、GNU coreutils、sedlstailcutはまだ完全に国際化されていませんが、これは主にUnicodeのサポートに関するものです。
たとえば、cutは、文字のサポートのために、ここでは末尾の代わりに使用するのに適した候補です。バイトまたは文字、_-c_(_--bytes_)および_-m_(_--chars_);を操作するためのオプションはありません。

_-m_/_--chars_のみがバージョンの時点で
cut (GNU coreutils) 8.21、2013、
実装されていません!

_info cut_から:

_`-c CHARACTER-LIST'
`--characters=CHARACTER-LIST'
     Select for printing only the characters in positions listed in CHARACTER-LIST.  
     The same as `-b' for now, but internationalization will change that.
_


これも参照してください answer to `cut -c`(` --characters`)はUTF-8で使用できませんか?

45
Volker Siegel

テキストがSTRINGというシェル変数にある場合、bashzshまたはmkshシェルでこれを行うことができます。

printf '%s\n' "${STRING:(-3)}"

または

printf '%s\n' "${STRING: -3}"

これは、その構文の由来であるksh93と連動するという利点もあります。

ポイントは、:-から分離する必要があるということです。それ以外の場合は、Bourne Shellの${var:-default}演算子になります。

zshまたはyashシェルでの同等の構文は次のとおりです。

printf '%s\n' "${STRING[-3,-1]}"
37
DopeGhoti

awkの使用:

awk '{ print substr( $0, length($0) - 2, length($0) ) }' file
ted
654
789
13
jasonwryan

文字列が変数内にある場合、次のことができます。

printf %s\\n "${var#"${var%???}"}"

次のように、$varの値から最後の3文字を取り除きます。

${var%???}

...そして$varすべての先頭から取り除きますbut次のように取り除かれたもの:

${var#"${var%???}"}

この方法には長所と短所があります。明るい面では、それは完全にPOSIXに移植可能であり、最新のシェルで動作するはずです。また、$varに3文字以上含まれていない場合nothingですが、末尾の\newlineが出力されます。次に、もしwantがその場合に出力された場合、次のような追加の手順が必要です。

last3=${var#"${var%???}"}
printf %s\\n "${last3:-$var}"

このようにして、$last3は、$varに含まれるバイト数が3以下の場合にのみ空になります。そして、$varは、$last3が空またはunsetである場合にのみ$last3に置き換えられます-設定しただけでunsetではないことがわかります。

11
mikeserv

あなたはこれを行うことができますが、これは少し...過度です:

for s in unlimited 987654 123456789; do
    rev <<< $s | cut -c 1-3 | rev
done 
ted
654
789
7
glenn jackman

Utf-8文字列の防弾ソリューション:

utf8_str=$'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82' # привет

last_three_chars=$(Perl -CAO -e 'print substr($ARGV[0], -3)' "$utf8_str")

または使用:

last_three_chars=$(Perl -MEncode -CO -e '
  print substr(decode("UTF-8", $ARGV[0], Encode::FB_CROAK), -3)
' "$utf8_str")

不正なデータ処理を防ぐため。

例:

Perl -MEncode -CO -e '
  print substr(decode("UTF-8", $ARGV[0], Encode::FB_CROAK), -3)
' $'\xd0\xd2\xc9\xd7\xc5\xd4' # koi8-r привет

このようなものを出力します:

utf8 "\xD0" does not map to Unicode at /usr/lib/x86_64-linux-gnu/Perl/5.20/Encode.pm line 175.

ロケール設定に依存しません(つまり、LC_ALL=C)。 Bashsedgrepawkrevには次のようなものが必要です:LC_ALL=en_US.UTF-8

一般的な解決策:

  • 受信バイト
  • エンコーディングを検出する
  • バイトを文字にデコードする
  • 文字を抽出する
  • 文字をバイトにエンコードする

chardet でエンコーディングを検出できます。 関連プロジェクト も参照してください。

Perlでは Encode 、Python 2.7では codecs でデコード/エンコードできます。

Utf-16le文字列から最後の3文字を抽出し、これらの文字をutf-8に変換します

utf16_le_str=$'\xff\xfe\x3f\x04\x40\x04\x38\x04\x32\x04\x35\x04\x42\x04' # привет

chardet <<<"$utf16_le_str"  # outputs <stdin>: UTF-16LE with confidence 1.0

last_three_utf8_chars=$(Perl -MEncode -e '
    my $chars = decode("utf-16le", $ARGV[0]);
    my $last_three_chars = substr($chars, -3);
    my $bytes = encode("utf-8", $last_three_chars);
    print $bytes;
  ' "$utf16_le_str"
)

参照: perlunitutPython 2 Unicode HOWTO

3

「expr」または「rev」の使用についてはどうですか?

@ G-Man によって提供されるものと同様の回答:expr "$yourstring" : '.*\(...\)$'これには、grepソリューションと同じ欠点があります。

よく知られているトリックは、「カット」と「回転」を組み合わせることです:echo "$yourstring" | rev | cut -n 1-3 | rev

1
gildux

tail -n 1 revisions.log | awk '{print substr($ 0、0、length($ 0)-(length($ 0)-13))}'

最初から13文字を印刷する場合

0

文字列のサイズを取得するには:

size=${#STRING}

次に、最後のn文字の部分文字列を取得します。

echo ${STRING:size-n:size}

例えば:

STRING=123456789
n=3
size=${#STRING}
echo ${STRING:size-n:size}

与えるでしょう:

789
0
Esref

文字列にスペースがある場合、printfは機能しません。

スペースのある文字列のコードの下

str="Welcome to Linux"
echo -n $str | tail -c 3

ヌクス

0
Saurabh