Получите длины нулей (прерванных одними)
У меня длинный столбец единиц и нулей:
0
0
0
1
0
0
0
0
0
1
0
0
0
0
0
1
0
0
1
....
Я могу легко получить среднее число нулей между ними (всего общее/одно):
ones=$(grep -c 1 file.txt)
lines=$(wc -l < file.txt)
echo "$lines / $ones" | bc -l
Но как я могу получить длину строк нулей между ними? В кратком примере выше это будет:
3
5
5
2
Ответы
Ответ 1
Изменить: исправлено для случая, когда последняя строка равна 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
Я бы включил uniq
для более легко читаемого подхода:
uniq -c file.txt | awk '/ 0$/ {print $1}'
Ответ 3
Используя 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}
Если поле не True, то есть, если поле 0
, увеличьте счетчик. Затем перейдите к следующей строке.
-
{if (s) print s; s=0}
в противном случае напечатайте значение счетчика и reset его, но только если оно содержит некоторое значение (чтобы избежать печати 0
, если файл начинается с 1
).
-
END {if (s) print s}
напечатайте оставшееся значение счетчика после обработки файла, но только если оно не было напечатано ранее.
Ответ 4
Если файл file.txt - это только столбец из них и нули, вы можете использовать awk
и изменить разделитель записи на "1\n". Это делает каждую "запись" последовательностью "0\n", а счетчик 0 в записи - это длина записи, деленная на 2. Подсчет будет правильным для начальных и конечных и нулей.
awk 'BEGIN {RS="1\n"} { print length/2 }' file.txt
Ответ 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
Ответ 6
Вы можете использовать awk
:
awk '$1=="0"{s++} $1=="1"{if(s)print s;s=0} END{if(s)print(s)}'
Объяснение:
Специальная переменная $1
содержит значение первого поля (столбца) строки текста. Если вы не укажете разделитель поля с помощью параметра командной строки -F
, он по умолчанию будет иметь значение wide - значение $1
будет содержать 0
или 1
в вашем примере.
Если значение $1
равно 0
, переменная с именем s
будет увеличиваться, но если $1
равна 1
, то текущее значение s
будет напечатано (если больше нуля) и повторно инициализируется до 0
. (Обратите внимание, что awk инициализирует s
с помощью 0
до первой операции приращения)
Блок END
запускается после обработки последней строки ввода. Если файл заканчивается на 0
(s), будет напечатан номер 0
между концом файла и последним 1
. (Без блока END
они не будут печататься)
Выход
3
5
5
2
Ответ 7
если вы можете использовать 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
Ответ 8
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.
Ответ 9
Другой способ:
perl -lnE 'if(m/1/){say $.-1;$.=0}' < file
"reset" счетчик строк, если 1
.
печатает
3
5
5
2
Ответ 10
Моя попытка. Не так красиво, но..: 3
grep -n 1 test.txt | gawk '{y=$1-x; print y-1; x=$1}' FS=":"
Из:
3
5
5
2
Ответ 11
Простейшим решением было бы использовать 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
Ответ 12
Смешной, в чистом Bash:
while read -d 1 -a u || ((${#u[@]})); do
echo "${#u[@]}"
done < file
Это говорит read
использовать 1
как разделитель, т.е. прекратить чтение, как только встретится 1
; read хранит 0
в полях массива u
. Тогда нам нужно только подсчитать количество полей в u
с помощью ${#u[@]}
. || ((${#u[@]}))
здесь на всякий случай, если ваш файл не заканчивается символом 1
.
Ответ 13
Более странный (и не полностью правильный) способ:
perl -0x31 -laE 'say @F+0' <file
печатает
3
5
5
2
0
Это
- читает файл с разделителем записей, устанавливается на символ
1
-0x31
- с autosplit
-a
(разбивает запись на массив @F
)
- и печатает количество элементов в
@F
, например. say @F+0
или может использовать say scalar @F
К сожалению, после окончательного 1
(как разделитель записей) он печатает пустую запись - поэтому печатает последний 0
.
Это неправильное решение, показывающее его только как альтернативное любопытство.
Ответ 14
Расширяя отличный ответ erickson, вы можете сказать:
$ uniq -c file | awk '!$2 {print $1}'
3
5
5
2
Из man uniq
мы видим, что цель uniq
заключается в следующем:
Отфильтровать соседние строки соответствия из INPUT (или стандартного ввода), написание к OUTPUT (или к стандартному выходу).
So 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
.