cut
コマンドは文字列の最初のn
文字を出力できることを知っていますが、最後のn
文字を選択するにはどうすればよいですか?
文字数が可変の文字列がある場合、文字列の最後の3文字だけを出力するにはどうすればよいですか。例えば。
必要な「無制限」出力は「テッド」 「987654」必要な出力は「654」 「123456789」必要な出力は「789」
なぜ誰も明白な答えを出していないのですか?
sed 's/.*\(...\)/\1/'
…または少しわかりにくい
grep -o '...$'
確かに、2つ目は3文字未満の行が消えてしまうという欠点があります。しかし、質問はこのケースの動作を明確に定義していませんでした。
文字を数えるためだけに、正規表現や複数のプロセスは必要ありません。
コマンドtail
は、ファイルの最後の行を表示するためによく使用されますが、オプション_-c
_(_--bytes
_)、これはこのための適切なツールのようです:
_$ printf 123456789 | tail -c 3
789
_
(シェルを使用している場合、tail
のプロセスの開始を節約できるため、mikeservの回答のようなメソッドを使用することには意味があります。)
次に、最後の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、sed
、ls
、tail
、cut
はまだ完全に国際化されていませんが、これは主に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で使用できませんか? 。
テキストがSTRING
というシェル変数にある場合、bash
、zsh
またはmksh
シェルでこれを行うことができます。
printf '%s\n' "${STRING:(-3)}"
または
printf '%s\n' "${STRING: -3}"
これは、その構文の由来であるksh93と連動するという利点もあります。
ポイントは、:
を-
から分離する必要があるということです。それ以外の場合は、Bourne Shellの${var:-default}
演算子になります。
zsh
またはyash
シェルでの同等の構文は次のとおりです。
printf '%s\n' "${STRING[-3,-1]}"
awk
の使用:
awk '{ print substr( $0, length($0) - 2, length($0) ) }' file
ted
654
789
文字列が変数内にある場合、次のことができます。
printf %s\\n "${var#"${var%???}"}"
次のように、$var
の値から最後の3文字を取り除きます。
${var%???}
...そして$var
すべての先頭から取り除きますbut次のように取り除かれたもの:
${var#"${var%???}"}
この方法には長所と短所があります。明るい面では、それは完全にPOSIXに移植可能であり、最新のシェルで動作するはずです。また、$var
に3文字以上含まれていない場合nothingですが、末尾の\n
ewlineが出力されます。次に、もしwantがその場合に出力された場合、次のような追加の手順が必要です。
last3=${var#"${var%???}"}
printf %s\\n "${last3:-$var}"
このようにして、$last3
は、$var
に含まれるバイト数が3以下の場合にのみ空になります。そして、$var
は、$last3
が空またはunset
である場合にのみ$last3
に置き換えられます-設定しただけでunset
ではないことがわかります。
あなたはこれを行うことができますが、これは少し...過度です:
for s in unlimited 987654 123456789; do
rev <<< $s | cut -c 1-3 | rev
done
ted
654
789
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
)。 Bash
、sed
、grep
、awk
、rev
には次のようなものが必要です: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"
)
「expr」または「rev」の使用についてはどうですか?
@ G-Man によって提供されるものと同様の回答:expr "$yourstring" : '.*\(...\)$'
これには、grepソリューションと同じ欠点があります。
よく知られているトリックは、「カット」と「回転」を組み合わせることです:echo "$yourstring" | rev | cut -n 1-3 | rev
tail -n 1 revisions.log | awk '{print substr($ 0、0、length($ 0)-(length($ 0)-13))}'
最初から13文字を印刷する場合
文字列のサイズを取得するには:
size=${#STRING}
次に、最後のn文字の部分文字列を取得します。
echo ${STRING:size-n:size}
例えば:
STRING=123456789
n=3
size=${#STRING}
echo ${STRING:size-n:size}
与えるでしょう:
789
文字列にスペースがある場合、printfは機能しません。
スペースのある文字列のコードの下
str="Welcome to Linux"
echo -n $str | tail -c 3
ヌクス