Как суммировать числа соответствия

Это - типичная проблема, которой это кажется на форуме AskUbuntu - в основном:


Эти терминальные команды должны решить Вашу проблему:

Сначала удалите Список Слияния путем открытия терминала (Нажмите Ctrl+Alt+T для запуска), и выполните эту команду:

sudo rm /var/lib/apt/lists/* -vf

Затем, генерируйте новый путем выполнения простого обновления:

sudo apt-get update

Вот отчет об ошибкахдругой) для этой проблемы, которая теперь решена так, это не должно создавать новые уродливые файлы, однако если у Вас уже есть уродливые файлы, необходимо удалить их, как объяснено в этом сообщении.

2
26.11.2018, 02:22
3 ответа

Вот один из способов посчитать, сколько 4, 5 или 6 появляется в вашем номере и заставить bash выполнить операцию, основываясь на том, два результата или нет:

$ con1=1457
$ a=${con1//[^456]/}; [ ${#a} -eq 2 ] && echo Yes
Yes
2
27.01.2020, 22:05

Начало работы

всякий раз, когда я Имейте проект, как это, я люблю приближаться к этому на этапах. Первое, что мне нравится делать, это добавить echo внутри петли, а затем запустить его, чтобы убедиться, что цикл дает мне то, что я хочу.

#! /bin/bash
for (( CON1=10000; CON1<=99999; CON1++ )) ;
do
  echo $CON1
done

Теперь, когда я бегу, я буду использовать голова -5 , чтобы просто показать первые 5 строк, которые он выводит.

$ ./cmd.bash | head -5
10000
10001
10002
10003
10004

Хорошо, так что выглядит хорошо, проверьте следующий конец:

$ ./cmd.bash | tail -5
99995
99996
99997
99998
99999

тоже выглядит хорошо. Итак, теперь давайте выясним некоторые способы приблизиться к следующему шагу идентификации номеров с 2 цифрами из множества {4,5,6}. Мой первый инстинкт здесь должен идти GREP . Есть также методы для этого чисто в Bash, но я люблю использовать различные инструменты, GREP , awk , и SED для выполнения этих типов вещей , в основном потому, что вот как мой разум работает.

Подход

Так как мы можем строки строк, которые содержат 2 цифры из множества, {4,5,6}? Для этого вы можете использовать заданный обозначение, который написан так, как это в Regex, [456]. Вы также можете указать, сколько цифр вы хотите сопоставить с этого набора. Это написано так:

[456]{#}

Где # - это номер или диапазон чисел. Если бы мы хотели 3, мы написали [456] {3} . Если мы хотели 2-5 цифр, мы написали [456] {2,5} . Если вы хотите 3 или более, [456] {3,} `.

Так что для вашего сценария это [456] {2} . Чтобы использовать регулярное выражение в GREP , ваша конкретная версия GREP необходимо для поддержки -E Swtich. Это обычно доступно в самом стандарте GREP .

$ echo "45123" | grep -E "[456]{2}"
45123

Кажется, работает, но если мы дадим его номера с 3, мы начинаем видеть проблему:

$ echo "45423" | grep -E "[456]{2}"
45423

это также соответствует. Это связано с тем, что GREP не имеет концепции того факта, что это цифры в строке. Это тупой. Мы сказали это, чтобы сказать нам, если серию символов в нашей строке из набора и что есть 2 из них, и в строке 2 цифры 45423 .

Это также не удается для этих строк:

$ echo "41412" | grep -E "[456]{2}"
$

Так что этот метод используется? Это если мы немного изменим тактику, но нам придется восстановить регельс.

Пример

$ echo -e "41123\n44123\n44423\n41423" | grep -E "[^456]*([456][^456]*){2}"
44123
44423
41423

Приведенное выше представляет 4 типа строк. ECHO -E "41123 \ N44123 \ N44423 \ N41423" Просто печатает 4 чисел из нашего диапазона.

$ echo -e "41123\n44123\n44423\n41423"
41123
44123
44423
41423

Как работает это Regex? Он устанавливает рисунок регулятора Regex ноль или более «не [456]», а затем 1 или более [456] или ноль или более «не [456]» символов, ищет 2 вхождения последних.

Так что теперь мы делаем небольшую сборку в вашем сценарии.

for (( CON1=10000; CON1<=99999; CON1++ )) ;
do
  if echo $CON1 | grep -q -E "[^456]*([456][^456]*){2}"; then
      echo $CON1
    fi
done

Использование нашей Head & Хвост Трюк сверху мы видим, что он работает:

$ ./cmd.bash | head -5
10044
10045
10046
10054
10055

$ ./cmd.bash | tail -5
99955
99956
99964
99965
99966

Но этот метод оказывается медленно. Проблема в том, что GreeP . Это дорого, и мы бегаем `grep 1 раз на итерацию через петлю, так что это ~ 80к раз!

Чтобы улучшить, что мы могли бы переместить нашу команду GREP за пределами цикла и запустить его 1 раз, после того, как список был сгенерирован, например, используя нашу оригинальную версию сценария, который просто повторил номера:

$ ./cmd.bash | grep -E "[^456]*([456][^456]*){2}"

Примечание: Мы могли полностью отбросить петлю и использовать инструмент командной строки, SEQ . Это будет генерировать ту же последовательность чисел, SEQ 10000 99999 .

Один вкладыш?

Модный способ сделать это, чтобы использовать последовательность чисел из вышеуказанной команды, а затем трубу ее в команду , которая будет вставить + между каждым числом, а затем запустить этот вывод в калькулятор командной строки, BC .

$ ./cmd.bash | grep -E "[^456]*([456][^456]*){2}" | paste -s -d"+"
10044+10045+10046+10054+10055+10056+10064+10065+10066+10144+10145+...

$ ./cmd.bash | grep -E "[^456]*([456][^456]*){2}" | paste -s -d"+" | bc
2409327540

Но это совершенно другой способ решить эту проблему, поэтому давайте вернемся к контуре для .

Использование чистого Bash

, поэтому нам нужен какой-то метод тестирования, если цифра имеет ровно 2 цифр в Bash, но не так дороже, как зовут GREP 80K Times. Современные версии Bash включают возможность совпадения с использованием оператора = ~ , что может сделать аналогичное сопоставление как GREP . Давайте посмотрим на это дальше.

#!/bin/bash
for (( CON1=10000; CON1<=99999; CON1++ )) ;
  if [[ $CON1 =~ [^456]*([456][^456]*){2} ]]; then
    echo $CON1
  fi
done

Беги запуска, чтобы сделать именно то, что мы хотим.

$ ./cmd1.bash  | head -5
10044
10045
10046
10054
10055

$ ./cmd1.bash  | tail -5
99955
99956
99964
99965
99966

Проверка, что он показывает, что он работает с 41511 сейчас:

$ ./cmd1.bash | grep 41511
41511

Ссылки

1
27.01.2020, 22:05

Эта команда работала в конце концов, выполнялась на моем beaglebone как root:

pkill -USR1 -n -x dd

Я мог запускать команду снова и снова, и она действительно будет обновляться (медленная передача).

Интересно, что обновление появится в окне other Terminal (то есть в окне, выполняющем команду dd):

Debian GNU/Linux 7

BeagleBoard.org BeagleBone Debian Image 2014-04-23

Support/FAQ: http://elinux.org/Beagleboard:BeagleBoneBlack_Debian
39136+0 records in
39136+0 records out
20037632 bytes (20 MB) copied, 5.6016 s, 3.6 MB/s
89376+0 records in
89376+0 records out
45760512 bytes (46 MB) copied, 12.3178 s, 3.7 MB/s
205152+0 records in
205152+0 records out
105037824 bytes (105 MB) copied, 27.7496 s, 3.8 MB/s
296608+0 records in
296608+0 records out
151863296 bytes (152 MB) copied, 40.7469 s, 3.7 MB/s
361184+0 records in
361184+0 records out
184926208 bytes (185 MB) copied, 49.3917 s, 3.7 MB/s
432672+0 records in
432672+0 records out
221528064 bytes (222 MB) copied, 58.9498 s, 3.8 MB/s
648529+0 records in
648529+0 records out
332046848 bytes (332 MB) copied, 88.3797 s, 3.8 MB/s
702289+0 records in
702289+0 records out
359571968 bytes (360 MB) copied, 103.606 s, 3.5 MB/s
987329+0 records in
987329+0 records out
505512448 bytes (506 MB) copied, 194.866 s, 2.6 MB/s
991001+0 records in
991001+0 records out
507392512 bytes (507 MB) copied, 197.19 s, 2.6 MB/s
-121--175418-

Getting start

Всякий раз, когда у меня есть такой проект, я хочу подходить к нему поэтапно. Первое, что я хотел бы сделать, это добавить эхо внутрь цикла, а затем запустить его, чтобы убедиться, что цикл дает мне то, что я хочу.

#! /bin/bash
for (( CON1=10000; CON1<=99999; CON1++ )) ;
do
  echo $CON1
done

Теперь, когда я запускаю его, я буду использовать head -5 , чтобы просто показать первые строки 5, которые он выводит.

$ ./cmd.bash | head -5
10000
10001
10002
10003
10004

Хорошо, так что выглядит хорошо, проверьте конец так:

$ ./cmd.bash | tail -5
99995
99996
99997
99998
99999

Это выглядит хорошо тоже. Теперь давайте выясним, пути мы могли бы подойти к следующему этапу идентификации чисел с 2 цифрами из набора {4,5,6}. Мой первый инстинкт здесь, чтобы пойти на grep . Есть также методы для этого чисто в Баше, но я люблю использовать различные инструменты, grep , awk и sed для выполнения таких вещей, главным образом потому, что так работает мой разум.

Подход

Так как мы можем grep строки, которые содержат 2 цифры из аппарата, {4,5,6}? Для этого можно использовать нотацию набора, которая написана так в regex, [456]. Можно также указать, сколько цифр должно совпадать с этим набором. Это написано так:

[456]{#}

Где # - число или диапазон чисел. Если бы мы хотели 3, мы бы написали [456] {3} . Если бы мы хотели 2-5 цифры, мы бы записали [456] {2,5} . Если требуется 3 или более, [456] {3,} '.

Таким образом, для вашего сценария это [456] {2} . Для использования регекса в grep необходимо, чтобы определенная версия grep поддерживала коммутатор -E . Обычно это доступно в большинстве стандартных grep .

$ echo "45123" | grep -E "[456]{2}"
45123

Кажется, что это работает, но если мы дадим ему числа с 3, мы начинаем видеть проблему:

$ echo "45423" | grep -E "[456]{2}"
45423

Это тоже совпадение. Это происходит потому, что grep не имеет понятия, что это цифры в последовательность. Это глупо. Мы сказали, чтобы он сказал нам, если серия символов в нашем ряде из набора и что есть 2 из них и есть 2 цифры в последовательность 45423 .

Это также не удается для этих последовательностей:

$ echo "41412" | grep -E "[456]{2}"
$

Так этот метод пригоден? Это если мы немного изменим тактику, но нам придется возродить регекс.

Пример

$ echo -e "41123\n44123\n44423\n41423" | grep -E "[^456]*([456][^456]*){2}"
44123
44423
41423

Выше представлены 4 типа последовательностей. echo-e «41123\n44123\n4423\n41423» просто печатает 4 числа из нашего диапазона.

$ echo -e "41123\n44123\n44423\n41423"
41123
44123
44423
41423

Как работает этот регекс? Он устанавливает образец regex, равное нулю или большему числу символов «not [456]», а затем 1 или большему числу символов [456] или нулю или большему количеству символов «not [456]», и ищет 2 вхождения последнего.

Теперь мы делаем небольшую сборку в вашем сценарии.

for (( CON1=10000; CON1<=99999; CON1++ )) ;
do
  if echo $CON1 | grep -q -E "[^456]*([456][^456]*){2}"; then
      echo $CON1
    fi
done

Используя нашу головную и хвостовую хитрость сверху, мы видим, что она работает:

$ ./cmd.bash | head -5
10044
10045
10046
10054
10055

$ ./cmd.bash | tail -5
99955
99956
99964
99965
99966

Но этот метод оказывается собачьим медленным. Проблема в том, что grep . Это дорого, и мы выполняем "grep 1 времени, за итерацию через цикл, так что это ~ 80 тысяч раз!

Чтобы улучшить то, что мы могли бы переместить нашу команду grep за пределы цикла и запустить ее 1 раз, после того, как список был создан, как это, используя нашу первоначальную версию сценария, который только что повторил числа:

$ ./cmd.bash | grep -E "[^456]*([456][^456]*){2}"

ПРИМЕЧАНИЕ: Мы могли бы удалить цикл for полностью и использовать инструмент командной строки, seq . При этом генерируется одна и та же последовательность чисел, seq 10000 99999 .

Один лайнер?

Модным способом для этого было бы использовать последовательность чисел из вышеуказанной команды, а затем направить ее в команду paste , которая вставляет + между каждым числом, а затем запустить этот вывод в калькулятор командной строки, bc .

$ ./cmd.bash | grep -E "[^456]*([456][^456]*){2}" | paste -s -d"+"
10044+10045+10046+10054+10055+10056+10064+10065+10066+10144+10145+...

$ ./cmd.bash | grep -E "[^456]*([456][^456]*){2}" | paste -s -d"+" | bc
2409327540

Но это совершенно другой способ решения этой проблемы, так что давайте вернемся к для цикла.

Использование чистого Bash

Поэтому нам нужен какой-то метод тестирования, если цифра имеет точно 2 цифры в Bash, но не так дорого, как вызов grep 80k раз. Современные версии Bash включают в себя возможность совпадения с помощью оператора = ~ , который может делать совпадение аналогично grep . Давайте посмотрим на это дальше.

#!/bin/bash
for (( CON1=10000; CON1<=99999; CON1++ )) ;
  if [[ $CON1 =~ [^456]*([456][^456]*){2} ]]; then
    echo $CON1
  fi
done

Выполнение этого действия делает именно то, что мы хотим.

$ ./cmd1.bash  | head -5
10044
10045
10046
10054
10055

$ ./cmd1.bash  | tail -5
99955
99956
99964
99965
99966

Проверка показывает, что он работает с 41511 сейчас:

$ ./cmd1.bash | grep 41511
41511

Ссылки

-121--133847-

Я полагаю, что вы должны сделать это в чистом сценарии Bash, но перевод алгоритма John1024 в awk дает значительное ускорение:

awk 'BEGIN{k=0;for(i=10000;i<100000;i++){j=i;if(gsub(/[456]/,"",j)==2)k+=i};print k}'

Это выполняется в менее чем 1/20 из Это также немного быстрее, чем версия Python, которая использует встроенный метод Python str.count () .

0
27.01.2020, 22:05

Теги

Похожие вопросы