Как группировать переменные на основе временного интервала? [закрыто]

в худшем случае вы всегда можете это сделать: размонтировать диск или массив и остановить любой массив.

dd if=/dev/sdX of=/dev/sdX iflag=direct,sync oflag=direct,sync

Это займет много времени, но должно работать.

В идеале вы можете запросить список дефектов роста жесткого диска (glist), но я не понял, как это сделать.

1
задан 14 September 2017 в 23:04

6 ответов

Мы можем сделать это полностью, используя только awk:

awk -F, 'BEGIN{print"\"Time Interval\",\"Count of Sources\""}NR>1{gsub(/"/,"",$2);h=int($2/10000)*10000;m=int(($2-h)/3000)*3000;ctr[h+m]++}END{n=asorti(ctr,idx);for(i=1;i<=n;i++){print "\""idx[i]"\",\""ctr[idx[i]]"\""}}' fb.csv

. Для данного входного файла fb.csv это приводит к выводу

"120000","4"
"123000","7"
"130000","8"
"133000","5"
"140000","7"

Важно: это для запуска GNU AWK (gawk) требуется использовать функцию asorti(...) для сортировки ассоциативных массивов по их индексам. Он не работает с mawk. Вы можете узнать свою версию по умолчанию awk с помощью awk -Wv.

Объяснение команды:

Мы запускаем awk, как это здесь , устанавливая разделитель полей, который разделяет столбцы на , и использует файл fb.csv в качестве входного сигнала:

awk -F, '<COMMAND>' fb.csv

Команда awk (placeholder <COMMAND> выше) является этим, после правильного форматирования :

BEGIN {
    print "\"Time Interval\",\"Count of Sources\""
}
NR>1 {
    gsub(/"/, "", $2)
    h = int($2 / 10000) * 10000
    m = int(($2-h) / 3000) * 3000
    ctr[h+m]++
}
END {
    n = asorti(ctr, idx)
    for(i=1; i<=n; i++) {
        print "\"" idx[i] "\",\"" ctr[idx[i]] "\""
    }
}

Это выглядит ужасно сложным (и я не могу отрицать, что это требует некоторой мысли, чтобы понять), поэтому я попытаюсь немного его сломать:

Кодовый блок BEGIN { ... } будет выполнен один раз перед чтением первой строки ввода из файла. Затем для каждой, кроме первой строки («номер строки больше 1»), выполняется блок NR>1 { ... }. Наконец, после того, как все данные будут прочитаны, блок END { ... } будет запущен.

Теперь блок BEGIN довольно прямолинейный, он печатает только новую строку заголовка CSV. Давайте посмотрим на блок NR>1. Помните, что awk разбивает каждую строку на поля, которые были разделены разделителем полей (тот, который мы установили в , с помощью аргумента -F). Первый столбец / поле будет сохранен в переменной $1, второй в $2 и так далее. Нас интересует только значение второго поля, которое содержит время. Используя функцию gsub(<PATTERN>, <REPLACEMENT>, <VARIABLE>), мы заменяем все вхождения <PATTERN> (регулярное выражение, заключенное в косые черты, здесь оно просто соответствует только кавычки) с помощью строки <REPLACEMENT> (пустой, как мы хотим их удалить) в [ f30] ($2, т.е. вторая поданная, содержащая время здесь). Затем мы декодируем временную метку в целые полные часы h (умноженное на 10000) и целых полчаса m (без полного часа, умноженное на 3000). Мы используем ассоциативный массив ctr в качестве счетчика того, как часто на входе появляется отметка округленного времени h+m. Наконец, в блоке END мы распечатываем значения счетчика, отсортированные по индексам округленной отметки времени.
1
ответ дан 22 May 2018 в 18:27
  • 1
    Он возвращает: awk: line 2: function asorti never defined. Я обнаружил, что эта функция принадлежит пакету gawk . После sudo apt install gawk функция доступна также для awk. – pa4080 15 September 2017 в 01:34
  • 2
    @Byte Commander Я попытался и мой вывод на время и счет: " 0 & quot ;, " 200 & quot ;. Есть проблема, и я не знаю, что это такое. – Ayu 15 September 2017 в 03:32
  • 3
    @Ayu Можете ли вы поделиться точным введенным вами материалом, чтобы я мог попытаться воспроизвести вашу проблему? Если ti длинный, возможно, загрузите его в pastebin.com вместо редактирования своего вопроса, чтобы добавить его. – Byte Commander 15 September 2017 в 09:18

Мы можем сделать это полностью, используя только awk:

awk -F, 'BEGIN{print"\"Time Interval\",\"Count of Sources\""}NR>1{gsub(/"/,"",$2);h=int($2/10000)*10000;m=int(($2-h)/3000)*3000;ctr[h+m]++}END{n=asorti(ctr,idx);for(i=1;i<=n;i++){print "\""idx[i]"\",\""ctr[idx[i]]"\""}}' fb.csv

. Для данного входного файла fb.csv это приводит к выводу

"120000","4" "123000","7" "130000","8" "133000","5" "140000","7"

Важно: это для запуска GNU AWK (gawk) требуется использовать функцию asorti(...) для сортировки ассоциативных массивов по их индексам. Он не работает с mawk. Вы можете узнать свою версию по умолчанию awk с помощью awk -Wv.

Объяснение команды:

Мы запускаем awk, как это здесь , устанавливая разделитель полей, который разделяет столбцы на , и использует файл fb.csv в качестве входного сигнала:

awk -F, '<COMMAND>' fb.csv

Команда awk (placeholder <COMMAND> выше) является этим, после правильного форматирования :

BEGIN { print "\"Time Interval\",\"Count of Sources\"" } NR>1 { gsub(/"/, "", $2) h = int($2 / 10000) * 10000 m = int(($2-h) / 3000) * 3000 ctr[h+m]++ } END { n = asorti(ctr, idx) for(i=1; i<=n; i++) { print "\"" idx[i] "\",\"" ctr[idx[i]] "\"" } }

Это выглядит ужасно сложным (и я не могу отрицать, что это требует некоторой мысли, чтобы понять), поэтому я попытаюсь немного его сломать:

Кодовый блок BEGIN { ... } будет выполнен один раз перед чтением первой строки ввода из файла. Затем для каждой, кроме первой строки («номер строки больше 1»), выполняется блок NR>1 { ... }. Наконец, после того, как все данные будут прочитаны, блок END { ... } будет запущен.

Теперь блок BEGIN довольно прямолинейный, он печатает только новую строку заголовка CSV. Давайте посмотрим на блок NR>1. Помните, что awk разбивает каждую строку на поля, которые были разделены разделителем полей (тот, который мы установили в , с помощью аргумента -F). Первый столбец / поле будет сохранен в переменной $1, второй в $2 и так далее. Нас интересует только значение второго поля, которое содержит время. Используя функцию gsub(<PATTERN>, <REPLACEMENT>, <VARIABLE>), мы заменяем все вхождения <PATTERN> (регулярное выражение, заключенное в косые черты, здесь оно просто соответствует только кавычки) с помощью строки <REPLACEMENT> (пустой, как мы хотим их удалить) в <VARIABLE> ($2, т.е. вторая поданная, содержащая время здесь). Затем мы декодируем временную метку в целые полные часы h (умноженное на 10000) и целых полчаса m (без полного часа, умноженное на 3000). Мы используем ассоциативный массив ctr в качестве счетчика того, как часто на входе появляется отметка округленного времени h+m. Наконец, в блоке END мы распечатываем значения счетчика, отсортированные по индексам округленной отметки времени.
1
ответ дан 18 July 2018 в 06:50

Мы можем сделать это полностью, используя только awk:

awk -F, 'BEGIN{print"\"Time Interval\",\"Count of Sources\""}NR>1{gsub(/"/,"",$2);h=int($2/10000)*10000;m=int(($2-h)/3000)*3000;ctr[h+m]++}END{n=asorti(ctr,idx);for(i=1;i<=n;i++){print "\""idx[i]"\",\""ctr[idx[i]]"\""}}' fb.csv

. Для данного входного файла fb.csv это приводит к выводу

"120000","4" "123000","7" "130000","8" "133000","5" "140000","7"

Важно: это для запуска GNU AWK (gawk) требуется использовать функцию asorti(...) для сортировки ассоциативных массивов по их индексам. Он не работает с mawk. Вы можете узнать свою версию по умолчанию awk с помощью awk -Wv.

Объяснение команды:

Мы запускаем awk, как это здесь , устанавливая разделитель полей, который разделяет столбцы на , и использует файл fb.csv в качестве входного сигнала:

awk -F, '<COMMAND>' fb.csv

Команда awk (placeholder <COMMAND> выше) является этим, после правильного форматирования :

BEGIN { print "\"Time Interval\",\"Count of Sources\"" } NR>1 { gsub(/"/, "", $2) h = int($2 / 10000) * 10000 m = int(($2-h) / 3000) * 3000 ctr[h+m]++ } END { n = asorti(ctr, idx) for(i=1; i<=n; i++) { print "\"" idx[i] "\",\"" ctr[idx[i]] "\"" } }

Это выглядит ужасно сложным (и я не могу отрицать, что это требует некоторой мысли, чтобы понять), поэтому я попытаюсь немного его сломать:

Кодовый блок BEGIN { ... } будет выполнен один раз перед чтением первой строки ввода из файла. Затем для каждой, кроме первой строки («номер строки больше 1»), выполняется блок NR>1 { ... }. Наконец, после того, как все данные будут прочитаны, блок END { ... } будет запущен.

Теперь блок BEGIN довольно прямолинейный, он печатает только новую строку заголовка CSV. Давайте посмотрим на блок NR>1. Помните, что awk разбивает каждую строку на поля, которые были разделены разделителем полей (тот, который мы установили в , с помощью аргумента -F). Первый столбец / поле будет сохранен в переменной $1, второй в $2 и так далее. Нас интересует только значение второго поля, которое содержит время. Используя функцию gsub(<PATTERN>, <REPLACEMENT>, <VARIABLE>), мы заменяем все вхождения <PATTERN> (регулярное выражение, заключенное в косые черты, здесь оно просто соответствует только кавычки) с помощью строки <REPLACEMENT> (пустой, как мы хотим их удалить) в <VARIABLE> ($2, т.е. вторая поданная, содержащая время здесь). Затем мы декодируем временную метку в целые полные часы h (умноженное на 10000) и целых полчаса m (без полного часа, умноженное на 3000). Мы используем ассоциативный массив ctr в качестве счетчика того, как часто на входе появляется отметка округленного времени h+m. Наконец, в блоке END мы распечатываем значения счетчика, отсортированные по индексам округленной отметки времени.
1
ответ дан 24 July 2018 в 18:41

Я уверен, что есть более элегантный способ, но мое предложение - создать исполняемый файл, назовем его counter.bash, с этим содержимым скрипта:

#!/bin/bash

echo '"Time Interval","Count of Sources"'
FILTRED=$(tail -n +2 "$1" | sed -e 's/^.*\,//' -e 's/"//g' | sort)
T=1

while [ $T -lt 24 ]; do

        ((T++)); R1=0; R2=0

        for i in $FILTRED; do

                hour=${i::-4}; minute=${i:2:-2}

                if [ "$T" -lt "10" ]; then TT="0${T}"; else TT="${T}"; fi

                if [ "$minute" -lt "30" ]; then
                        if [ "$hour" == "$TT" ]; then ((R1++)); fi
                else
                        if [ "$hour" == "$TT" ]; then ((R2++)); fi
                fi
        done

        if [ "$R1" -ne "0" ]; then echo "\"${TT}0000\",\"$R1\""; fi
        if [ "$R2" -ne "0" ]; then echo "\"${TT}3000\",\"$R2\""; fi
done

Затем запустите:

./counter.bash fb.csv

Если результат адекватен, перенаправляйте вывод в новый файл:

./counter.bash fb.csv > fb.counted.csv

Я сравнил работу ответа Байтового Командующего, и это скрипт, оба применены к тому же не столь огромному файлу. Они просто несравнимы:

$ cat fb.csv | wc -l
3304


$ time awk -F, 'BEGIN{print"\"Time Interval\",\"Count of Sources\""}NR>1{gsub(/"/,"",$2);h=int($2/10000)*10000;m=int(($2-h)/3000)*3000;ctr[h+m]++}END{n=asorti(ctr,idx);for(i=1;i<=n;i++){print "\""idx[i]"\",\""ctr[idx[i]]"\""}}' fb.csv

"Time Interval","Count of Sources"
"120000","672"
"123000","672"
"130000","560"
"133000","560"
"140000","839"

real    0m0.017s
user    0m0.012s
sys     0m0.000s


$ time ./counter.bash fb.csv

"Time Interval","Count of Sources"
"120000","672"
"123000","672"
"130000","560"
"133000","560"
"140000","839"

real    0m2.374s
user    0m2.368s
sys     0m0.000s

Когда файл действительно огромный, мой скрипт просто сработает (в разных строках) через некоторое время:

$ cat fb.csv | wc -l
9303745


$ time awk -F, 'BEGIN{print"\"Time Interval\",\"Count of Sources\""}NR>1{gsub(/"/,"",$2);h=int($2/10000)*10000;m=int(($2-h)/3000)*3000;ctr[h+m]++}END{n=asorti(ctr,idx);for(i=1;i<=n;i++){print "\""idx[i]"\",\""ctr[idx[i]]"\""}}' fb.csv

"Time Interval","Count of Sources"
"120000","1892288"
"123000","1892290"
"130000","1576904"
"133000","1576905"
"140000","2365357"

real    0m23.193s
user    0m23.080s
sys     0m0.096s


$ time ./counter.bash fb.csv

"Time Interval","Count of Sources"
./counter.bash: line 17: [: .0.138.1: integer expression expected
^C
real    2m27.992s
user    2m27.940s
sys     0m1.636s
0
ответ дан 22 May 2018 в 18:27
  • 1
    Спасибо @ pa4080. Я попытался запустить скрипт bash. Но я получил ошибку " ./ counter.bash: строка 21: [integer expression expected & quot ;. Как это решить? благодаря – Ayu 15 September 2017 в 03:03
  • 2
    @Ayu, просто используйте подход awk :) – pa4080 15 September 2017 в 03:09
  • 3
    Я попытался, но это мой вывод: «Временной интервал», «Count Of Sources», & Quot; 0 & Quot;, & Quot; 200 & Quot ;. Есть проблема, и я не знаю, что это такое. – Ayu 15 September 2017 в 03:30
  • 4
    @Ayu, возможно, что-то не так с форматом файла. В какой ОС она генерируется? Не могли бы вы поделиться им как файл где-нибудь, я попробую его дома, позже этим вечером. – pa4080 15 September 2017 в 09:44
  • 5
    Я уже нашел проблему. В формате была проблема, и она уже исправлена. благодаря – Ayu 15 September 2017 в 09:59

Я уверен, что есть более элегантный способ, но мое предложение - создать исполняемый файл, назовем его counter.bash, с этим содержимым скрипта:

#!/bin/bash echo '"Time Interval","Count of Sources"' FILTRED=$(tail -n +2 "$1" | sed -e 's/^.*\,//' -e 's/"//g' | sort) T=1 while [ $T -lt 24 ]; do ((T++)); R1=0; R2=0 for i in $FILTRED; do hour=${i::-4}; minute=${i:2:-2} if [ "$T" -lt "10" ]; then TT="0${T}"; else TT="${T}"; fi if [ "$minute" -lt "30" ]; then if [ "$hour" == "$TT" ]; then ((R1++)); fi else if [ "$hour" == "$TT" ]; then ((R2++)); fi fi done if [ "$R1" -ne "0" ]; then echo "\"${TT}0000\",\"$R1\""; fi if [ "$R2" -ne "0" ]; then echo "\"${TT}3000\",\"$R2\""; fi done

Затем запустите:

./counter.bash fb.csv

Если результат адекватен, перенаправляйте вывод в новый файл:

./counter.bash fb.csv > fb.counted.csv

Я сравнил работу ответа Байтового Командующего, и это скрипт, оба применены к тому же не столь огромному файлу. Они просто несравнимы:

$ cat fb.csv | wc -l 3304 $ time awk -F, 'BEGIN{print"\"Time Interval\",\"Count of Sources\""}NR>1{gsub(/"/,"",$2);h=int($2/10000)*10000;m=int(($2-h)/3000)*3000;ctr[h+m]++}END{n=asorti(ctr,idx);for(i=1;i<=n;i++){print "\""idx[i]"\",\""ctr[idx[i]]"\""}}' fb.csv "Time Interval","Count of Sources" "120000","672" "123000","672" "130000","560" "133000","560" "140000","839" real 0m0.017s user 0m0.012s sys 0m0.000s $ time ./counter.bash fb.csv "Time Interval","Count of Sources" "120000","672" "123000","672" "130000","560" "133000","560" "140000","839" real 0m2.374s user 0m2.368s sys 0m0.000s

Когда файл действительно огромный, мой скрипт просто сработает (в разных строках) через некоторое время:

$ cat fb.csv | wc -l 9303745 $ time awk -F, 'BEGIN{print"\"Time Interval\",\"Count of Sources\""}NR>1{gsub(/"/,"",$2);h=int($2/10000)*10000;m=int(($2-h)/3000)*3000;ctr[h+m]++}END{n=asorti(ctr,idx);for(i=1;i<=n;i++){print "\""idx[i]"\",\""ctr[idx[i]]"\""}}' fb.csv "Time Interval","Count of Sources" "120000","1892288" "123000","1892290" "130000","1576904" "133000","1576905" "140000","2365357" real 0m23.193s user 0m23.080s sys 0m0.096s $ time ./counter.bash fb.csv "Time Interval","Count of Sources" ./counter.bash: line 17: [: .0.138.1: integer expression expected ^C real 2m27.992s user 2m27.940s sys 0m1.636s
0
ответ дан 18 July 2018 в 06:50

Я уверен, что есть более элегантный способ, но мое предложение - создать исполняемый файл, назовем его counter.bash, с этим содержимым скрипта:

#!/bin/bash echo '"Time Interval","Count of Sources"' FILTRED=$(tail -n +2 "$1" | sed -e 's/^.*\,//' -e 's/"//g' | sort) T=1 while [ $T -lt 24 ]; do ((T++)); R1=0; R2=0 for i in $FILTRED; do hour=${i::-4}; minute=${i:2:-2} if [ "$T" -lt "10" ]; then TT="0${T}"; else TT="${T}"; fi if [ "$minute" -lt "30" ]; then if [ "$hour" == "$TT" ]; then ((R1++)); fi else if [ "$hour" == "$TT" ]; then ((R2++)); fi fi done if [ "$R1" -ne "0" ]; then echo "\"${TT}0000\",\"$R1\""; fi if [ "$R2" -ne "0" ]; then echo "\"${TT}3000\",\"$R2\""; fi done

Затем запустите:

./counter.bash fb.csv

Если результат адекватен, перенаправляйте вывод в новый файл:

./counter.bash fb.csv > fb.counted.csv

Я сравнил работу ответа Байтового Командующего, и это скрипт, оба применены к тому же не столь огромному файлу. Они просто несравнимы:

$ cat fb.csv | wc -l 3304 $ time awk -F, 'BEGIN{print"\"Time Interval\",\"Count of Sources\""}NR>1{gsub(/"/,"",$2);h=int($2/10000)*10000;m=int(($2-h)/3000)*3000;ctr[h+m]++}END{n=asorti(ctr,idx);for(i=1;i<=n;i++){print "\""idx[i]"\",\""ctr[idx[i]]"\""}}' fb.csv "Time Interval","Count of Sources" "120000","672" "123000","672" "130000","560" "133000","560" "140000","839" real 0m0.017s user 0m0.012s sys 0m0.000s $ time ./counter.bash fb.csv "Time Interval","Count of Sources" "120000","672" "123000","672" "130000","560" "133000","560" "140000","839" real 0m2.374s user 0m2.368s sys 0m0.000s

Когда файл действительно огромный, мой скрипт просто сработает (в разных строках) через некоторое время:

$ cat fb.csv | wc -l 9303745 $ time awk -F, 'BEGIN{print"\"Time Interval\",\"Count of Sources\""}NR>1{gsub(/"/,"",$2);h=int($2/10000)*10000;m=int(($2-h)/3000)*3000;ctr[h+m]++}END{n=asorti(ctr,idx);for(i=1;i<=n;i++){print "\""idx[i]"\",\""ctr[idx[i]]"\""}}' fb.csv "Time Interval","Count of Sources" "120000","1892288" "123000","1892290" "130000","1576904" "133000","1576905" "140000","2365357" real 0m23.193s user 0m23.080s sys 0m0.096s $ time ./counter.bash fb.csv "Time Interval","Count of Sources" ./counter.bash: line 17: [: .0.138.1: integer expression expected ^C real 2m27.992s user 2m27.940s sys 0m1.636s
0
ответ дан 24 July 2018 в 18:41
  • 1
    Спасибо @ pa4080. Я попытался запустить скрипт bash. Но я получил ошибку & quot; ./ counter.bash: строка 21: [integer expression expected & quot ;. Как это решить? благодаря – Ayu 15 September 2017 в 03:03
  • 2
    @Ayu, просто используйте подход awk :) – pa4080 15 September 2017 в 03:09
  • 3
    Я попытался, но это мой вывод: «Временной интервал», «Count Of Sources», & Quot; 0 & Quot;, & Quot; 200 & Quot ;. Есть проблема, и я не знаю, что это такое. – Ayu 15 September 2017 в 03:30
  • 4
    @Ayu, возможно, что-то не так с форматом файла. В какой ОС она генерируется? Не могли бы вы поделиться им как файл где-нибудь, я попробую его дома, позже этим вечером. – pa4080 15 September 2017 в 09:44
  • 5
    Я уже нашел проблему. В формате была проблема, и она уже исправлена. благодаря – Ayu 15 September 2017 в 09:59

Другие вопросы по тегам:

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