我有一长串的零和零:
0
0
0
1
0
0
0
0
0
1
0
0
0
0
0
1
0
0
1
....
我可以轻松获得1之间的平均零数(只有总数/ 1):
ones=$(grep -c 1 file.txt)
lines=$(wc -l < file.txt)
echo "$lines / $ones" | bc -l
但是如何在两者之间获得零串的长度呢?在上面的简短示例中,它将是:
3
5
5
2
答案 0 :(得分:17)
我要包含uniq
以便更轻松地阅读:
uniq -c file.txt | awk '/ 0$/ {print $1}'
答案 1 :(得分:10)
编辑:已修复最后一行为0
的情况简单的awk:
awk '/1/{print NR-prev-1; prev=NR;}END{if (NR>prev)print NR-prev;}'
在bash中也不是那么困难:
i=0
for x in $(<file.txt); do
if ((x)); then echo $i; i=0; else ((++i)); fi
done
((i)) && echo $i
答案 2 :(得分:7)
使用awk
,我会使用值为0
的字段评估为False的事实:
awk '!$1{s++; next} {if (s) print s; s=0} END {if (s) print s}' file
返回:
3
5
5
2
另外,请注意END
块以打印任何&#34;剩余的&#34;在最后1
之后出现的零。
!$1{s++; next}
如果字段不为True,即字段为0
,则递增计数器。然后,跳到下一行。{if (s) print s; s=0}
否则,打印计数器的值并重置它,但它只包含一些值(如果文件以0
开头,则为了避免打印1
。 / LI>
END {if (s) print s}
在处理完文件后打印计数器的剩余值,但前面没有打印过。答案 3 :(得分:5)
如果你的file.txt 只是一列1和0,你可以使用awk
并将记录分隔符更改为&#34; 1 \ n&#34;。这使得每个&#34;记录&#34;一个&#34; 0 \ n&#34;的序列,记录中0的计数是记录的长度除以2.对于前导和尾随的1和0,计数是正确的。
awk 'BEGIN {RS="1\n"} { print length/2 }' file.txt
答案 4 :(得分:5)
今天这似乎是非常受欢迎的问题。加入晚会,这是另一个简短的gnu-awk命令来完成这项工作:
awk -F '\n' -v RS='(1\n)+' 'NF{print NF-1}' file
3
5
5
2
工作原理:
-F '\n' # set input field separator as \n (newline)
-v RS='(1\n)+' # set input record separator as multipled of 1 followed by newline
NF # execute the block if minimum one field is found
print NF-1 # print num of field -1 to get count of 0
答案 5 :(得分:3)
您可以使用awk
:
awk '$1=="0"{s++} $1=="1"{if(s)print s;s=0} END{if(s)print(s)}'
<强>解释强>
特殊变量$1
包含一行文本的第一个字段(列)的值。除非您使用-F
命令行选项指定字段分隔符,否则默认为宽空格 - 意味着$1
在您的示例中将包含0
或1
。
如果$1
的值等于0
,则名为s
的变量会增加,但如果$1
等于1
,则s
的当前值1}}被打印(如果大于零)并重新初始化为0
。 (请注意,awk在第一次递增操作之前用s
初始化0
在处理完最后一行输入后执行END
块。如果文件以0
(s)结尾,则会打印文件结尾与最后0
之间1
的数量。 (没有END
块,他们就不会打印)
<强>输出强>:
3
5
5
2
答案 6 :(得分:3)
如果您可以使用perl
:
perl -lne 'BEGIN{$counter=0;} if ($_ == 1){ print $counter; $counter=0; next} $counter++' file
3
5
5
2
awk
相同逻辑实际上看起来更好:
awk '$1{print c; c=0} !$1{c++}' file
3
5
5
2
答案 7 :(得分:3)
Pure bash:
sum=0
while read n ; do
if ((n)) ; then
echo $sum
sum=0
else
((++sum))
fi
done < file.txt
((sum)) && echo $sum # Don't forget to output the last number if the file ended in 0.
答案 8 :(得分:3)
另一种方式:
perl -lnE 'if(m/1/){say $.-1;$.=0}' < file
&#34;重置&#34; 1
时的行计数器。
打印
3
5
5
2
答案 9 :(得分:2)
我的尝试。不是那么漂亮但是......:3
grep -n 1 test.txt | gawk '{y=$1-x; print y-1; x=$1}' FS=":"
输出:
3
5
5
2
答案 10 :(得分:2)
最简单的解决方案是将sed
与awk
一起使用,如下所示:
sed -n '$bp;/0/{:r;N;/0$/{h;br}};/1/{x;bp};:p;/.\+/{s/\n//g;p}' input.txt \
| awk '{print length}'
<强>解释强>
sed
命令将0
分开并创建如下输出:
000
00000
00000
00
管道传输到awk '{print length}'
,您可以为每个间隔获得0
的计数:
<强>输出:强>
3
5
5
2
答案 11 :(得分:2)
一个有趣的,纯粹的Bash:
while read -d 1 -a u || ((${#u[@]})); do
echo "${#u[@]}"
done < file
这告诉read
使用1
作为分隔符,即在遇到1
时立即停止阅读; read将0
存储在数组u
的字段中。然后,我们只需要使用u
计算${#u[@]}
中的字段数。 || ((${#u[@]}))
就是为了防止您的文件以1
结尾。
答案 12 :(得分:2)
更奇怪(而且不完全正确)的方式:
perl -0x31 -laE 'say @F+0' <file
打印
3
5
5
2
0
它
1
-0x31
-a
(将记录拆分为数组@F
)@F
中的元素数量,例如say @F+0
或可以使用say scalar @F
不幸的是,在最后的1
(作为记录分隔符)后,它会打印一个空记录 - 因此会打印最后一个0
。
这是不正确的解决方案,仅作为替代好奇心显示出来。
答案 13 :(得分:2)
扩展erickson's excellent answer,您可以说:
$ uniq -c file | awk '!$2 {print $1}'
3
5
5
2
从man uniq
我们看到uniq
的目的是:
从INPUT(或标准输入)过滤相邻的匹配线,写入 输出(或标准输出)。
所以uniq
对这些数字进行分组。使用-c
选项,我们得到一个带有出现次数的前缀:
$ uniq -c file
3 0
1 1
5 0
1 1
5 0
1 1
2 0
1 1
然后是在0
之前打印那些计数器的问题。为此,我们可以使用awk
之类的:awk '!$2 {print $1}'
。即:如果字段为0
,则打印第二个字段。