Группировать и подсчитывать имена файлов по шаблону

Проблема с ответом Томаша заключается в том, что уничтожение pid процесса, который говорит, что getty, вероятно, ничего не сделает. Если ваш inittab настроен на «перезагрузку», что обычно происходит с getty, то даже если вам удастся его убить, Linux перезапустит его.

Одно из решений — закомментировать строку inittab:

#AMA0:12345:respawn:/bin/start_getty 115200 ttyAMA0 vt102

Затем скажите процессу инициализации обновить inittab:

kill -HUP 1

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

for pid in $(ls -l /proc/[0-9]*/fd/* | grep /dev/ttyAMA0 | awk '{ print $9 }' | awk -F/ '{ print $3 }'); do
    echo "killing $pid"
    kill -9 $pid
done

Теперь порт будет освобожден, и вы сможете использовать его как последовательный порт.

Чтобы просто выяснить, какие pids вам нужно убить, чтобы освободить порт, вы можете ввести:

ls -l /proc/[0-9]*/fd/* | grep /dev/ttyAMA0
2
29.09.2021, 14:31
6 ответов
for f in my_file_*_*.txt
do
    f="${f#my_file_}"
    printf "%s\n" "${f%%_*.txt}"
done |
sort |
uniq -c

Цикл forпереформатирует каждое имя файла fдля удаления начального my_file_и конечного _whatever.txt, затем сортирует этот вывод и использует uniqдля подсчета количества вхождений каждого уникального значения.

3
29.09.2021, 19:36

Предполагая, что ваши имена файлов «хорошо -себя ведут», т. е. они не содержат новых строк, следующая комбинация lsи awkбудет работать:

ls -d my_file* | awk -F'_' 'NF==4{count[$3]++} END{for (i in count) printf "%s: %d\n", i, count[i]}'

Это перенаправит вывод команды ls, которая содержит список всех файлов, начиная с my_file*, в программу awk. Программа awkбудет использовать _в качестве разделителя полей и проверит 3-е поле, чтобы отследить вхождение в массив count, который использует номер группы в качестве «индекса массива».

В конце выводится обзор частоты появления каждой группы.

Уведомление

  • Существует «минимальная» защита от полностью искаженных имен файлов, требующая ровно 4 таких поля. Это предполагает, что _не может быть частью a, d, f,... части имен файлов в вашем примере.
  • Вывод не обязательно будет сортироваться в соответствии с именами категорий. Порядок сортировки будет зависеть от того, как awkпроходит индексы массива в цикле for (i in count). Если сортировка желательна, вы можете добавить еще один канал к sort. В качестве альтернативы, если вы используете GNU Awk, вы можете добавить параметр конфигурации через
    BEGIN{PROCINFO["sorted_in"]="@ind_str_asc"}
    
    до правила NF==4{...}. Это обеспечит обход массивов в соответствии с индексом массива, отсортированным в лексикографическом (ASCII )порядке.
  • Это будет работать с ограничением, указанным в начале, а также потому, что структура имени вашего файла довольно проста. Как правило, не рекомендуется анализировать выводls.
6
29.09.2021, 14:57

Имя файла, содержащее четыре поля, разделенных символом подчеркивания -, и заканчивающееся строкой .txt, соответствует расширенному шаблону подстановки +([!_])_+([!_])_+([!_])_+([!_]).txt. Каждый +([!_])соответствует одному или нескольким символам подчеркивания, отличным от -, точно так же, как [^_]+соответствует расширенному регулярному выражению.

Мы можем извлечь третье поле из этого, удалив первые два поля и последнее поле вместе со строкой суффикса .txt.

#!/bin/bash

shopt -s extglob nullglob

names=( +([!_])_+([!_])_+([!_])_+([!_]).txt )
names=( "${names[@]#+([!_])_+([!_])_}" )
names=( "${names[@]%_+([!_]).txt}" )

printf '%s\n' "${names[@]}" | sort | uniq -c

Сценарий только предполагает, что третье поле в имени файла не содержит встроенных новых строк.

Тестирование на примерах имен файлов в вопросе:

$ ls
list              my_file_A_f.txt   my_file_B_x.txt   my_file_D_g.txt
my_file_A_a.txt   my_file_A_t.txt   my_file_C_f.txt   my_file_E_r.txt
my_file_A_d.txt   my_file_B_r.txt   my_file_D_f.txt   script
$./script
   4 A
   2 B
   1 C
   2 D
   1 E

Вы можете отфильтровать это с помощью простого awkскрипта, чтобы преобразовать его в любой желаемый формат.

$./script | awk '{ printf "%s: %d\n", $2, $1 }'
A: 4
B: 2
C: 1
D: 2
E: 1

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

#!/bin/bash

shopt -s extglob nullglob

printf '%s\n' +([!_])_+([!_])_+([!_])_+([!_]).txt |
cut -d _ -f 3 | sort | uniq -c
1
29.09.2021, 18:57

Использование Raku (, ранее известного как Perl _6)

raku -e '.say for dir.split("_")[2,5,8...*].Bag.pairs.sort;'

Пример ввода (Список текущего каталога):

my_file_A_a.txt
my_file_A_d.txt
my_file_A_f.txt
my_file_A_t.txt
my_file_B_r.txt
my_file_B_x.txt
my_file_C_f.txt
my_file_D_f.txt
my_file_D_g.txt
my_file_E_r.txt

Пример вывода:

A => 4
B => 2
C => 1
D => 2
E => 1

В качестве краткого пояснения, текущий каталог dir()получается и разделяется на _символом подчеркивания. [Предполагается, что имена файлов не начинаются/не заканчиваются символом подчеркивания _]. Таким образом, получаемые элементы:

raku -e 'dir.split("_").raku.say;'

("my", "file", "A", "a.txt my", "file", "A", "d.txt my", "file", "A", "f.txt my", "file", "A", "t.txt my", "file", "B", "r.txt my", "file", "B", "x.txt my", "file", "C", "f.txt my", "file", "D", "f.txt my", "file", "D", "g.txt my", "file", "E", "r.txt").Seq

После этого Raku имеет довольно надежный механизм для создания/понимания последовательностей :просто ввод [2,5,8...*]позволяет вытягивать буквыA,B,C,D,E(через каждый третий элемент, нумерация начинается с0). Затем Bag, pairsи sort.

(Если вы уверены, что в именах ваших файлов нет пробелов, вы можете добавить второй вызов split(" ")после первого. Тогда элементы, которые вы вытащите, будут[2,6,10...*]).

ПРИМЕЧАНИЕ 1 :Если у вас есть посторонние имена файлов, которые не соответствуют шаблону, указанному в OP (, и портят ваши подсчеты ), вы можете изменить вызов dirна что-то вроде dir(test => / [ <-[_]>+ _ ] ** 3 /), который подмножает имена файлов в регулярном выражении, где за одним -или -более не -символами подчеркивания следует символ подчеркивания, повторяющийся три раза.

ПРИМЕЧАНИЕ 2 :Если вам нужны два столбца вывода (без =>в -между ), просто измените .sayна .put. Или, если вы предпочитаете более похожий на Раку -вывод, попробуйте использовать .raku.say, который возвращает следующее:

:A(4)
:B(2)
:C(1)
:D(2)
:E(1)

https://docs.raku.org/routine/dir
https://docs.raku.org/type/Bag
https://raku.org

1
29.09.2021, 19:17

Я бы подошел к этому с помощью цикла по подстановочному знаку, а затем извлек бы поле из имени файла с помощью функции регулярных выражений bash в его[[конструкции условного выражения .

unset collect
declare -A collect
for f in./*_*_*_*.txt
do 
  [[ $f =~ [^_]+_+[^_]+_+([^_]+)_+[^_]+.txt ]] &&
  ((collect["${BASH_REMATCH[1]}"]++))
done

for group in "${!collect[@]}"
do
  printf '%s: %d\n' "$group" "${collect["$group"]}"
done

Единственным полем в круглых скобках является 3-е поле с подчеркиванием -с разделителем; после захвата мы увеличиваем это значение в ассоциативном массиве(collect).

3
29.09.2021, 19:40

Сортировка, сортировка и достаточно уникальный:

ls |grep my_file | sed "s/.*_.*_\(.*\)_.*txt/\1/"|sort |uniq -c|sed "s/[^0-9]*\([0-9]*\) \(.*\)/\2: \1/"

Еще один лайнер, всего 3 переменные:

count=0;chchange="dummy";ls | sed -n "s/.*my_file.*_\(.*\)_.*txt/\1/p"|sort|cat - <(echo end) |while read a ; do  if [ $a == $chchange ] ; then  ((count++));else if [ $chchange != "dummy" ] ;then  echo "$chchange $count"; fi; count=1; chchange=$a; fi;  done;

Необходимо добавить одну дополнительную строку в вывод сортировки.

-1
30.09.2021, 08:35

Теги

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