Вы можете сделать это с помощью awk
,чей match()
, который устанавливает переменные RSTART
и RLENGTH
, весьма полезен для этого:
<mySequence.fasta awk -v C=N '{
i=0
while (match($0, C "+")) {
printf "Position %d %s %d\n", i+RSTART, C, RLENGTH
i += RSTART+RLENGTH-1
$0 = substr($0, RSTART+RLENGTH)
}}'
Или с помощью perl
с использованием массивов @-
и @+
, записывающих начало и конец совпадений:
perl -ne 'printf "Position %d N %d\n", $-[0]+1, $+[0]-$-[0] while /N+/g'
Еще один немного более быстрый (по крайней мере, с моей версиейperl
)perl
подхода с использованием(экспериментального)(?{...})
оператора регулярного выражения:
perl -ne '0 while /N(?{$s=pos})N*(?{printf "Position %d N %s\n", $s, pos()-$s+1})/g'
Я недостаточно использую сценарии оболочки, но часто делаю подобные вещи на других языках. Я дам кое-что, чтобы помочь вам организовать ваши поиски.
1 -Вам нужно проанализировать CSV-файл
Вы можете посмотреть, как анализировать CSV-файл по этой ссылке :https://stackoverflow.com/questions/4286469/how-to-parse-a-csv-file-in-bash
2 -Вам нужно получить строки, совпадающие со словом «прочитано»
Вы можете использовать подобные регулярные выражения и адаптировать некоторые критерии, чтобы получить оценку выше 20,2:
/\b(\w*read\w*)\b/g
Поместите его на этот сайт, чтобы получить информацию о выражении:https://regexr.com/
3 -Вам необходимо отсортировать вывод по критерию
Для этого можно использовать команду sort . Это проще, чем присваивать массиву и сортировать этот массив.
4 -Перенаправление выхода
Вы можете легко перенаправить вывод оболочки в файл с помощью чего-то вроде «script.sh > my _output.txt». Или сделайте это внутри вашего скрипта 'var > output.txt'
Учусь awk
, поэтому жду отзывов от мудрецов:
cat file | tr -s ' ' | awk -F, 'BEGIN { print "Score ID" } tolower($4) ~ /read/ { if($5 >= 20) print $5,$9 }' > output
В этом случае, чтобы иметь возможность использовать формат OP, замените все пробелы только одним
tr -s ' '
Использовать запятую в качестве разделителя:
-F,
Чтобы сделать сравнение нечувствительным к регистру:
tolower($4)
В четвертом столбце есть строка "прочитано"
tolower($4) ~ /read/
Если значение пятого столбца равно или больше 20, выведите:
if($5>=20) print $5,$9
Добавить заголовок (Сейчас пытаюсь сделать это с помощьюawk
)
BEGIN { print "Score ID" }
Выход
score ID
24 1
39 2
Если вы хотите "использовать команды оболочки",классическим решением будет конвейер с grep, cut и sort. Некоторые заметки о необходимых шагах (Я частично протестировал):
Во-первых, вы cut
сокращаете число столбцов/полей до трех необходимых.
С помощью grep
вы выполняете "анализ". Это «читается» только как целое слово? деликатный случай? Значение оценки можно довольно легко проверить в том же регулярном выражении (после вырезания ). Что-то вроде:
grep "\<[Rr]ead\>.*,.*[2-9][0-9].*,"
Это работает, но вы можете видеть пределы этого "простого" подхода. Оценка «-20» будет считаться «выше 20» (, поскольку она имеет «абсолютное значение 20 или выше», так сказать )
.С помощью sort
вы... сортируете оставшиеся строки, используя на этот раз реальное числовое значение. Это делает команду (pipe )похожей на:
cut OPT FILE | grep "regex" | cut OPT2 | sort OPT >report.txt
Я даже не говорю, что это хорошее решение. Но это должно быть весьма полезно для «обрезки» и «фильтрации» больших файлов, а также для демонстрации.
с использованием Миллера(https://github.com/johnkerl/miller)и начиная с
D,E,F,message,score,A,B,C,ID
d,e,f,Let's read a book,24,a,b,c,1
j,k,l,Read this book,39,d,e,f,2
m,n,o,Have you read this book?,15,g,h,i,3
и работает
mlr --csv filter -S '$message=~"(r|R)ead" && $score>20' then cut -f score,ID input.csv >output.csv
у вас будет
score,ID
24,1
39,2
Некоторые подробности о команде:
--csv
, чтобы установить формат ввода и вывода filter -S '$message=~"(r|R)ead" && $score>20'
, чтобы применить фильтр cut -f score,ID
для выбора полей Если у вас неверный CSV-файл, в котором ячеек больше, чем столбцов заголовков, например
D,E,F,message,score,A,B,C,ID
d,e,f,Let's read a book,24,a,b,c,1
j,k,l,Read this book,39,d,e,f,2,a wrong cell,another wrong cell
m,n,o,Have you read this book?,15,g,h,i,3
вы можете применить опцию ragged
и запустить
mlr --csv --ragged unsparsify then filter -S '$message=~"(r|R)ead" && $score>20' then cut -f score,ID input.csv>output.csv
Однако, если у вас возникли проблемы с файлом CSV, лучше всего опубликовать его здесь целиком
Немного awk
, немного регулярного выражения и убираем пробелы, перенаправляя их кcolumn
awk -F',' '{if ( $4 ~ /[Rr]ead/ && $5 > 20 || NR==1) print $5, $9}' data.csv | column -t
Объяснение.... после установки разделителя полей на a с помощью-F','
....если 4-е поле соответствует регулярному выражению ~
с «Читать» или «прочитано» и &&
5-е поле > 20 или ||
мы находимся в первой строке (с заголовки )NR==1
, затем распечатайте интересующие вас столбцы......
Просто так
Если вы знаете заголовки столбцов, но ленитесь считать....
Загрузить заголовки в ассоциативный массив
declare -A HEADS=( [mess]=mess [id]=ID [score]=score )
..... awk
вывести индексы столбцов из первой строки файла данных в массив
for j in "${!HEADS[@]}"; do HEADS[$j]=$(awk -F',' -v s=${HEADS[$j]} 'NR==1 {for (i=1; i<=NF; ++i) { if ($i ~ s ) print i }}' data.csv) ; done
... вернуться к началу просто вставив индексы в awk
как переменные
awk -v mess=${HEADS[mess]} -v score=${HEADS[score]} -v id=${HEADS[id]} -F',' '{if ( $mess ~ /[Rr]ead/ && $score >20 || NR==1) print $score, $id}' data.csv | column -t