Bash 获取零的长度(被1打断)

Bash 获取零的长度(被1打断),bash,awk,Bash,Awk,我有一长列1和0: 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 .... 我可以很容易地得到1之间0的平均数(仅为总数/1): 编辑:修复了最后一行为0的情况 awk中的Easy: 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;

我有一长列1和0:

0
0
0
1
0
0
0
0
0
1
0
0
0
0
0
1
0
0
1
....
我可以很容易地得到1之间0的平均数(仅为总数/1):


编辑:修复了最后一行为0的情况

awk中的Easy:

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 
i=0

对于美元形式的x(您可以使用
awk

awk '$1=="0"{s++} $1=="1"{if(s)print s;s=0} END{if(s)print(s)}'
说明:

-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
特殊变量
$1
包含一行文本的第一个字段(列)的值。除非您使用
-F
命令行选项指定字段分隔符,否则它默认为宽空间,这意味着
$1
在您的示例中将包含
0
1

如果
$1
的值等于
0
,则称为
s
的变量将递增,但如果
$1
等于
1
,则打印
s
的当前值(如果大于零)并重新初始化为
0
。(请注意,在第一次增量操作之前,awk使用
0
初始化
s

END
块在处理完最后一行输入后执行。如果文件以
0
(s)结尾,则将打印文件结尾和最后一行
1
之间的
0
s个数。(如果没有
END
块,则不会打印)

输出

3
5.
5.
2.

如果可以使用
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
如果file.txt只是一列1和0,则可以使用
awk
并将记录分隔符更改为“1\n”。这使每个“记录”都是一个“0\n”序列,记录中的0的计数是记录长度除以2。前导和尾随的1和0的计数是正确的

awk 'BEGIN {RS="1\n"} { print length/2 }' file.txt

使用
awk
,我将使用值为
0
的字段计算为False的事实:

awk '!$1{s++; next} {if (s) print s; s=0} END {if (s) print s}' file
这将返回:

3
5
5
2
另外,请注意
END
块以打印最后一个
1
之后出现的任何“剩余”零

解释
  • !$1{s++;next}
    如果字段为非真,即如果字段为
    0
    ,则递增计数器。然后跳到下一行
  • {if(s)print s;s=0}
    否则,打印计数器的值并将其重置,但前提是它包含一些值(以避免在文件以
    1
    开头时打印
    0
  • END{if(s)print s}
    在处理文件后打印计数器的剩余值,但前提是之前没有打印
    • 纯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.
      
      sum=0
      读;做
      如果((n));那么
      回音$sum
      总和=0
      其他的
      ((++sum))
      fi
      完成
      我的尝试。不太漂亮,但

      grep -n 1 test.txt | gawk '{y=$1-x; print y-1; x=$1}' FS=":"
      
      输出:

      另一种方式:

      perl -lnE 'if(m/1/){say $.-1;$.=0}' < file
      

      这似乎是今天相当流行的问题。加入党晚了,这里有另一个简短的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
      

      为了更容易阅读,我将包括
      uniq

      uniq -c file.txt | awk '/ 0$/ {print $1}'
      

      最简单的解决方案是将
      sed
      awk
      一起使用,如下所示:

      sed -n '$bp;/0/{:r;N;/0$/{h;br}};/1/{x;bp};:p;/.\+/{s/\n//g;p}' input.txt \
        | awk '{print length}'
      
      说明:

      -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
      
      sed
      命令分离
      0
      s并创建如下输出:

      sed -n '$bp;/0/{:r;N;/0$/{h;br}};/1/{x;bp};:p;/.\+/{s/\n//g;p}' input.txt \
        | awk '{print length}'
      
      000
      00000
      00000
      00
      
      通过管道输送到
      awk'{print length}'
      可以获得每个间隔的
      0
      计数:

      输出:

      -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
      
      3
      5.
      5.
      2.
      
      一个有趣的例子,在纯Bash中:

      while read -d 1 -a u || ((${#u[@]})); do
          echo "${#u[@]}"
      done < file
      
      read-d1-a u | |(${#u[@]})时做什么
      回声“${u[@]}”
      完成<文件
      
      这告诉
      read
      使用
      1
      作为分隔符,即在遇到
      1
      时立即停止读取;read将
      0
      存储在数组
      u
      的字段中。然后我们只需要用
      ${u[@]}
      计算
      u
      中的字段数。
      |(${u[})
      在这里只是为了防止您的文件不是以一种更奇怪(且不完全正确)的方式结束:

      • 将记录分隔符设置为character
        1
        the
        -0x31
      • 使用自动拆分
        -a
        (将记录拆分为数组
        @F
      • 并打印
        @F
        中的元素数,例如
        说@F+0
        或可以使用
        说scalar@F
      不幸的是,在最后一个
      1
      (作为记录分隔符)之后,它会打印一个空记录,因此会打印最后一个
      0

      这是一个不正确的解决方案,只显示为另一种好奇心。

      展开,您可以说:

      $ uniq -c file | awk '!$2 {print $1}'
      3
      5
      5
      2
      
      man uniq
      我们可以看出
      uniq
      的目的是:

      从输入(或标准输入)中过滤相邻的匹配行,写入 输出(或标准输出)

      因此,
      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

      ,则打印第二个字段。您熟悉
      awk
      吗?不,我对此非常陌生。但是,根据答案(我目前正在浏览),看起来学习它会非常有帮助。:)谢谢潜伏者和所有人的回答。看起来我应该学习一些
      awk
      :)注意
      s=0
      是默认值,所以没有必要设置它!我以为默认情况下(在awk中)它应该是
      1
      …谢谢!需要一个结束块(如果文件以一些零结尾怎么办?)在两个
      print
      操作中都应该是
      if(s)print s
      。否则将输出一个(s)空行
      $ uniq -c file | awk '!$2 {print $1}'
      3
      5
      5
      2
      
      $ uniq -c file
            3 0
            1 1
            5 0
            1 1
            5 0
            1 1
            2 0
            1 1