Проблема с ответом Томаша заключается в том, что уничтожение 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
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
для подсчета количества вхождений каждого уникального значения.
Предполагая, что ваши имена файлов «хорошо -себя ведут», т. е. они не содержат новых строк, следующая комбинация 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
, который использует номер группы в качестве «индекса массива».
В конце выводится обзор частоты появления каждой группы.
Уведомление
_
не может быть частью a
, d
, f
,... части имен файлов в вашем примере. awk
проходит индексы массива в цикле for (i in count)
. Если сортировка желательна, вы можете добавить еще один канал к sort
. В качестве альтернативы, если вы используете GNU Awk, вы можете добавить параметр конфигурации через BEGIN{PROCINFO["sorted_in"]="@ind_str_asc"}
до правила NF==4{...}
. Это обеспечит обход массивов в соответствии с индексом массива, отсортированным в лексикографическом (ASCII )порядке. ls
. Имя файла, содержащее четыре поля, разделенных символом подчеркивания -, и заканчивающееся строкой .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
Использование 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
Я бы подошел к этому с помощью цикла по подстановочному знаку, а затем извлек бы поле из имени файла с помощью функции регулярных выражений 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
).
Сортировка, сортировка и достаточно уникальный:
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;
Необходимо добавить одну дополнительную строку в вывод сортировки.