Answers:
为什么没人给出明显的答案?
sed 's/.*\(...\)/\1/'
……或不太明显
grep -o '...$'
诚然,第二个缺点是,少于三个字符的行消失了。但问题并未明确定义此案例的行为。
echo "unlimited" | python -c "print raw_input()[-3:]"
"echo unlimited" | java -jar EnterpriseWordTrimmer.jar
,但是我认为并不需要引入更重的语言来进行字符操作。
java -server -Xms300M -Xmx3G -XX:+UseParallelGC -cp /path/to/all/the/jars/ -Dinput.interactive=false -Dinput.pipe=true -Dconfig.file=/path/to/config/last-three-letters.cfg -jar ...
grep -o -P '.{0,3}$'
即使该行少于3个字符,也将打印最后3个字符。-P
避免必须逃脱括号。
我们不应该只需要一个正则表达式或一个以上的过程来计算字符。
该命令tail
通常用于显示文件的最后几行,它具有一个选项-c
(--bytes
),它似乎恰恰是实现此目的的正确工具:
$ printf 123456789 | tail -c 3
789
(在外壳程序中时,使用类似mikeserv的方法是有意义的,因为这样可以省去启动的过程tail
。)
现在,您要求输入最后三个字符;这不是您的答案:它输出最后三个字节!
只要每个字符是一个字节,tail -c
就可以工作。因此,如果字符集是或变体ASCII
,则可以使用它ISO 8859-1
。
如果您使用通用UTF-8
格式的Unicode输入,则结果是错误的:
$ printf 123αβγ | tail -c 3
�γ
在此示例中,使用UTF-8
,希腊字母alpha,beta和gamma是两个字节长:
$ printf 123αβγ | wc -c
9
该选项-m
至少可以计算真实的unicode字符:
printf 123αβγ | wc -m
6
好的,所以最后6个字节将为我们提供最后3个字符:
$ printf 123αβγ | tail -c 6
αβγ
因此,tail
它不支持处理常规字符,甚至不尝试(请参见下文):它处理大小可变的行,但不处理大小可变的字符。
让我们这样说:tail
对于要解决的问题的结构来说是正确的,而对于数据的类型则是错误的。
进一步看,事实证明,你的coreutils GNU的基本工具,收集喜欢的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.
cut
似乎只有您和glenn jackman的解决方案似乎没有。
tail
应该处理字节而不是字符。我曾经打过补丁,添加了一个新的选项来选择字符,但是我相信从来没有合并过:-/
tail -c3 -n10 /var/log/syslog
tail -c3 -n10 /var/log/syslog
要求最后10行,这对我有用。您使用该选项-c3
,然后使用冲突的选项-n10
。后面的选项优先。
如果您的文本是在被称为shell变量STRING
,你可以在一个做到这一点bash
,zsh
或mksh
外壳:
printf '%s\n' "${STRING:(-3)}"
要么
printf '%s\n' "${STRING: -3}"
这也可以与语法来自的ksh93一起使用。
重点是:
必须与分开-
,否则它将成为${var:-default}
Bourne shell 的运算符。
zsh
或yash
shell中的等效语法为:
printf '%s\n' "${STRING[-3,-1]}"
${STRING:(-3):3}
(指定长度字段),${STRING: -3}
(在:
和之间有一个空格-
)或${STRING: -3:3}
。
3
有点麻烦,因为它要求“从最后一个字符起第三个字符,包括最后一个字符,这三个字符”实际上与“从最后一个字符起第三个字符开始的所有字符”相同, 包括的”。
如果字符串在变量中,则可以执行以下操作:
printf %s\\n "${var#"${var%???}"}"
这样会从$var
like 的值中去除最后三个字符:
${var%???}
...然后从$var
所有东西的头部剥离,但只是像这样剥离:
${var#"${var%???}"}
这种方法有其优点和缺点。从好的方面来说,它是完全POSIX便携式的,并且可以在任何现代外壳中使用。另外,如果$var
不包含至少三个字符没什么,但后\n
打印ewline。再一次,如果您希望在这种情况下将其打印出来,则需要执行以下附加步骤:
last3=${var#"${var%???}"}
printf %s\\n "${last3:-$var}"
这样,$last3
如果$var
包含3个或更少的字节,则永远为空。并且$var
仅替换为$last3
if $last3
为空或unset
-并且我们知道不是unset
因为我们只是设置了它而已。
printf
格式字符串的任何原因是什么?
${VARNAME:(-3)}
(假定bash
)?
bash
声称POSIX可映射性的任何其他外壳一样有效。
csh
是不是跻身现代,POSIX兼容的壳我在这里提到,很遗憾。POSIX-shell规范是根据建模的ksh
,该规范是在结合csh
了传统的Bourne风格的外壳之后进行建模的。ksh
结合了csh
出色的作业控制功能和旧的Bourne风格的I / O重定向。它还增加了一些东西-例如我上面演示的字符串操作概念。csh
我很遗憾地说,就我所知,这不可能在任何传统中都可行。
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
常见解决方案:
您可以使用Perl中的Encode和Python 2.7中的编解码器进行解码/编码
范例:
从utf-16le字符串中提取最后三个字符,并将这些字符转换为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"
)
echo
是您的防弹源吗?
decode/encode
是我的防弹源。整理我的答案。
LC_ALL=C
,因为这是一个非常“愚蠢”的设置,但是当你试图将一个UTF-8字符串传递给SHIFT-5它可能会破坏或SHIFT-5串KOI8等
perl -CAO -e 'print substr($ARGV[0], -3)'
很好。A
@ARGV元素应为以UTF-8编码的字符串,O
STDOUT将为UTF-8。
utf8_str
尾-n 1版本.log | awk'{print substr($ 0,0,length($ 0)-(length($ 0)-13))}'
如果要从头开始打印前十三个字符
如果字符串中包含空格,printf将不起作用。
下面的代码带空格
str="Welcome to Linux"
echo -n $str | tail -c 3
努克斯
printf
不工作,那么你正在做的事情非常错误的。
printf $str
(而不是printf "$str"
or printf '%s' "$str"
)。而且,是的,这printf $str
是非常错误的。(echo -n $str
不是好多了。)
grep -o '.\{3\}$'