tr -c \\n 1 <testfile | #first transform every [^\n] char to a 1
grep -nF '' | #next get line numbers
paste -d: - testfile | #then paste it together with itself
sort -t: -nk2,2 #then sort on second field
...获胜者似乎是第2行。
2:1111:4for
4:11111:five!
1:1111111:seven/7
3:11111111:8 eight?
但是这样做的问题是,每一行的长度都必须超过一倍才能正常工作-因此LINE_MAX实际上减半了。原因是它正在使用-什么是基数1?-代表线的长度。一种类似的(也许更整洁的)方法可能是在流中压缩该信息。我想到的第一个想法是,我应该这样unexpand
做:
tr -c \\n \ <testfile | #transform all [^\n] to <space>
unexpand -t10 | #squeeze every series of 10 to one tab
grep -nF '' | #and get the line numbers
sed 's/:/!d;=;:/;h;:big #sed compares sequential lines
$P;$!N; /\(:[^ ]*\)\( *\)\n.*\1.*\2/!D #newest line is shorter or...
g;/:./!q;b big' | #not; quit input entirely for blank line
sed -f - -e q testfile #print only first occurrence of shortest line
打印...
2
4for
另一个,就是sed
:
sed -n '/^\n/D;s/\(.\)\(\n.*\)*/\1/g
$p;h; s// /g;G;x;n;//!g;H;s// /g
G; s/^\( *\)\(\n \1 *\)\{0,1\}\n//
D' <infile >outfile
该语法符合标准-但这不能保证任何旧版本sed
都可以\(reference-group\)\{counts\}
正确处理-许多版本则不能。
它基本上将相同的正则表达式重复应用于输入-当需要编译它们时,这将非常有益。该模式是:
\(.\)\(\n.*\)*
它以不同的方式匹配不同的字符串。例如:
string1\nstring2\nstring3
...与s
in \1
和in中''
的空字符串匹配\2
。
1\nstring2\nstring3
...与1
in \1
和\nstring2\nstring3
in 匹配\2
\nstring2\nstring3
...与\n
in \1
和in中''
的空字符串匹配\2
。如果\n
在模式空间的开头有可能出现ewline,这将是有问题的/^\n/D
,但是使用和//!g
命令可以防止这种情况的发生。我确实使用过,[^\n]
但是对于这个小脚本的其他需求使可移植性成为一个问题,并且我对它经常被误解的许多方式不满意。另外,.
速度更快。
\nstring2
string1
...匹配\n
并s
再次输入\1
,都获得的''
空字符串\2
。空行根本不匹配。
当以g
叶状方式应用图案时,两个偏差(最左侧的标准偏差和较小的右侧\n
背线偏差)将相互抵消以实现跳过。一些例子:
s/\(.\)\(\n.*\)*/\1:\2/g
s/\(.\)\(\n.*\)*/\2\1:/g
s/\(.\)\(\n.*\)*/\1: /g
s/\(.\)\(\n.*\)*/ :\2/g
...如果全部(不是连续地)应用于以下字符串...
string1\nstring2
...将其转换为...
s:t:r:i:n:g:1:\nstring2
s:t:r:i:n:g:\nstring21:
s:t:r:i:n:g:1:
: : : : : : :\nstring2
基本上,我使用regexp始终只处理我要应用到的任何模式空间中的第一行。这样一来,我就可以兼顾保留的最短匹配线和最新线的两个不同版本,而无需借助测试循环-所应用的每个替换都可以立即处理整个模式空间。
文字/字符串比较需要不同的版本-因此,每行必须有一个版本,保证所有字符都相等。但是,当然,如果一个或另一个实际上应该是输入中最早出现的最短行,那么打印到输出的行可能应该是该行的原始版本,而不是我为了比较而进行过消毒/均质化的行。因此,我每个人都需要两个版本。
不幸的是,另一个必要条件是需要进行很多缓冲区切换以处理相同的缓冲区-但至少两个缓冲区都不会超过保持最新状态所需的四行-因此也许这并不可怕。
无论如何,对于每个循环,发生的第一件事是在记住的行上进行转换-因为实际保存的唯一副本是原义文字-转换为...
^ \nremembered line$
...然后,n
ext输入行将覆盖所有旧缓冲区。如果它至少不包含单个字符,则将其有效地忽略。只q
用第一个出现的空白行会容易得多,但是,嗯,我的测试数据有很多,所以我想处理多个段落。
因此,如果它确实包含一个字符,则其文字版本将附加到记住的行上,并且其隔开的比较版本将位于模式空间的开头,如下所示:
^ \n \nremembered line\nnew$
最后,将替换应用于该模式空间:
s/^\( *\)\(\n \1 *\)\{0,1\}\n//
因此,如果换行符可以容纳包含至少要保留一个字符的记住的行所需的空间,则前两行将被替换掉,否则仅替换第一行。
不管结果如何,模式空间中的第一行总是D
在循环结束时被选中,然后再次开始。这意味着如果新行比最后一行短,那么...
new
...被发送回循环中的第一个替换项,该替换项将始终仅从第一个换行符开始-保持完整。但是如果不是,那么字符串...
remembered line\nnew
...将改为开始下一个循环,并且第一个替换项将删除字符串...
\nnew
...每次。
在最后一行,将记住的行打印为标准输出,因此对于给出的示例数据,它打印:
4for
但是,认真使用tr
。