我想知道如何使用来grep
显示以相同字符开头和结尾的所有行。
答案1
POSIXly:
pattern='\(.\).*\1
.'
grep -x -- "$pattern" file
如果行以无效字节字符开始或结束,它将不起作用,如果您想覆盖这种情况,您可以添加LC_ALL=C
,尽管LC_ALL=C
仅适用于单字节字符数据。
perl6
似乎是最好的工具,如果你的盒子里有它的话:
$ printf '\ue7\u301 blah \u107\u327\n121\n1\n123\n' |
perl6 -ne '.say if m/^(.).*$0$/ || /^.$/'
ḉ blah ḉ
121
1
尽管它仍然因无效字符而窒息。
请注意,这perl6
将通过将文本转换为以下形式来更改文本NFC
:
$ printf '\u0044\u0323\u0307\n' |
perl6 -pe '' |
perl -CI -ne 'printf "U+%04x\n", ord for split //'
U+1e0c
U+0307
U+000a
$ printf '\u0044\u0323\u0307\n' |
perl -pe '' |
perl -CI -ne 'printf "U+%04x\n", ord for split //'
U+0044
U+0323
U+0307
U+000a
在内部,perl6
以形式存储字符串NFG
(代表Normalization Form Grapheme
),这是perl6
正确处理未预先组合的字素的发明方法:
$ printf '\u0044\u0323\u0307\n' | perl6 -ne '.chars.say'
1
$ printf '\u0044\u0323\u0307\n' | perl6 -ne '.codes.say'
2
答案2
不是 grep 而是 awk:
awk -F "" 'NF && $1 == $NF'
这些特殊情况的处理:
- 它不打印空行
- 它总是打印 1 个字符的行
空 FS 将记录拆分为gawk
、mawk
和中每个字段一个字符(字节,不是后两者的字符),但不是标准的,并且在由 A、W 和 K 等从原始记录派生的busybox
awk
实现中不起作用awk
关于 BSD 和商业 Unices。更便携,但更容易打字:
awk '/./ && substr($0,1,1) == substr($0,length)'
答案3
grep -xe '\(.\).*\1' -e .
例子:
$ printf '%s\n' il y était cet été | grep -xe '\(.\).*\1' -e .
y
été
-x
是为了精确的匹配(整行匹配)。\1
是对 中捕获的角色的反向引用\(.\)
。我们添加 a-e .
来处理包含单个字符的行的特殊情况。
它假设输入包含当前区域设置中的有效文本。
比赛正在进行中特点, 不是字节(例如 UTF-8 中的 é 是两个字节 0xc3 0xa9),也不是字素簇e
(例如,如果这些 é 以分解形式书写,后跟 U+0301 结合尖锐的重音符号,则它将不起作用)。
要使用grep
支持-P
PCRE 的 graphem 集群,请执行以下操作:
$ printf 'e\u0301te\u0301\n' | grep -xPe '(\X).*\1|\X'
été
假设两个簇的分解是相同的,例如ḉ
表示为的a 与表示为or ( )或( )或 ḉ ( )c
U+0301
U+0327
的一个不匹配。为此,您需要对规范化形式进行检查:c
U+0327
U+0301
ć
U+0107
U+0327
ç
U+00E7
U+0301
U+1E09
$ printf '\ue7\u301 blah \u107\u327\n' |
perl -MUnicode::Normalize -C -ne '
print if /^\X$/ || NFC($_) =~ /^(\X).*\1$/'
ḉ blah ḉ
答案4
快速 python2 替代方案:
python -c 'import sys;[sys.stdout.write(l) for l in sys.stdin if len(l)>1 and l.rstrip("\n").endswith(l[0])]' < input.txt
例子:
$ python -c 'import sys;[sys.stdout.write(l) for l in sys.stdin if len(l)>1 and l.rstrip("\n").endswith(l[0])]' < input.txt | cat -A
nathan$
ookie $
a line a$