У меня есть файл, который похож на это:
2_00003 R034671 31.25 96 55 2 100 195 77 161 7e-07 47.8
2_00003 R034668 31.25 96 55 2 100 195 77 161 7e-07 47.8
2_00003 R034667 31.25 96 55 2 100 195 77 161 7e-07 47.8
2_00003 R034665 31.25 96 55 2 100 195 77 161 7e-07 47.8
2_00003 R034656 34.88 86 45 2 100 185 77 151 9e-07 47.4
2_00003 R034662 34.88 86 45 2 100 185 77 151 9e-07 47.4
2_00003 R034659 34.88 86 45 2 100 185 77 151 9e-07 47.4
2_00004 R014991 31.90 232 141 5 2 232 4 219 5e-28 111
2_00004 R009910 31.90 232 141 5 2 232 4 219 5e-28 111
Я хочу выбрать просто первые строки групп, которые запускаются с той же строки в первом столбце. Таким образом для вышеупомянутого файла я хочу выбрать:
2_00003 R034671 31.25 96 55 2 100 195 77 161 7e-07 47.8
2_00004 R014991 31.90 232 141 5 2 232 4 219 5e-28 111
Я думавший использовать просто
uniq -w 7 <file name>
Но у меня есть две проблемы:
uniq
отчеты всегда первое вхождение (в моем случае в первой строке) Совет?
Вы можете рассмотреть использование sort -u
в качестве альтернативы uniq
, указав в качестве ключа первое поле, разделенное пробелами:
$ sort -uk1,1 file
2_00003 R034671 31.25 96 55 2 100 195 77 161 7e-07 47.8
2_00004 R014991 31.90 232 141 5 2 232 4 219 5e-28 111
В качестве альтернативы, вы можете сделать что-то подобное в awk
:
awk '$1!=last {last=$1; print}' file
, который проверяет первое поле каждой строки ($1
) на соответствие значению last
и печатает строку при каждом изменении $1
, обновляя значение last
по мере его поступления. [ 1111]
Можно сделать это в сценарии как это:
first_occurence.sh (устанавливает его, чтобы быть исполняемым файлом)
#!/bin/bash
# Set bash to separate words by newlines only, not spaces
IFS= Выполнение путем передачи по каналу файла в:
./first_occurence.sh < filename
\n'
# read input
input=("$(cat)")
# get a list of unique keys - split input by space with awk for any length
unique_values=($(printf "%s\n" "${input[*]}" | awk -F' ' '{ print $1 }' | uniq))
cur=0
# check each line of input for the key
for line in ${input[@]};
do
# wildcard matching
if [[ "$line" == "${unique_values[$cur]}"* ]]
then
# print line if match, and move on to checking the next key
printf "%s\n" "$line"
cur=$((cur + 1))
fi
# break the loop if we have used up all of our unique keys (only duplicates remain)
if [ $cur -ge ${#unique_values[@]} ]
then
break
fi
done
Выполнение путем передачи по каналу файла в:
./first_occurence.sh < filename
Я думаю, что решение Steeldriver с использованием sort
является лучшим, хотя, если вы хотите попробовать что-то еще, проверьте следующий скрипт Python:
#!/usr/bin/python2
import re
def checking():
if not check_list:
result.append(list_of_lines[index - 1])
with open('/path/to/the/file') as f:
list_of_lines = f.readlines()
result = []
for index in range(1, len(list_of_lines)):
regex_current = re.search('^[0-9]_[0-9]+', list_of_lines[index])
regex_previous = re.search('^[0-9]_[0-9]+', list_of_lines[index - 1])
check_list = [x for x in result if x.split()[0] == regex_previous.group()]
if regex_current == regex_previous:
checking()
else:
checking()
print ''.join(result)
Другой подход Python:
#!/usr/bin/env python3
import sys
file = sys.argv[1]
with open(file) as src:
lines = src.readlines()
for l in [[l for l in lines if l.startswith(f)][0] for f in set([l.split()[0] for l in lines])]:
print(l, end = "")
Выполните его с текстовым файлом как аргумент:
python3 <script> <text_file>
Хотя опция выше оказывается быстрым (протестированный на файле> 1 000 000 строк), это может быть решительно быстрее (appr. 15% в тестах, которые я запустил), если мы можем принять строку в первом столбце, не происходит на других положениях в записях (вероятно, безопасное предположение). В этом случае мы можем пропустить startswith()
функция:
#!/usr/bin/env python3
import sys
file = sys.argv[1]
with open(file) as src:
lines = src.readlines()
for l in [[l for l in lines if f in l][0] for f in set([l.split()[0] for l in lines])]:
print(l, end = "")