#awk #sed #grep
Вопрос:
У меня есть несколько больших файлов с двумя столбцами (разделенными табуляцией). Содержимое этих файлов выглядит следующим образом:
рабочий файл-1
K00001 0.188
K00005 15.97
K00008 188.09
файл сопоставления
K00001
K00002
K00003
K00004
K00005
K00006
K00007
K00008
диапазон файлов сопоставления составляет K00001 — K25804
Я хочу сопоставить свой working_file-1 с файлом сопоставления, чтобы результат выглядел так:
K00001 0.188
K00002
K00003
k00004
K00005 15.97
K00006
K00007
k00008 188.09
Пробелы (K0 отсутствует в working_file) могут быть заполнены нулем (если это возможно) или могут быть оставлены пустыми.
До сих пор я пробовал эти коды, следуя другим аналогичным постам (но безуспешно).:
awk 'NR==FNR {a[$1] ; next} $1 in a' mapping file working_file-1 > output.file
grep -Fw -f mapping file working_file-1 > output.file
редактировать: вывод работы od -c1; карта od -c
0000000 K 0 0 0 0 1 r n K 0 0 0 0 2 r n
0000020 K 0 0 0 0 3 r n K 0 0 0 0 4 r n
0000040 K 0 0 0 0 5 r n K 0 0 0 0 6 r n
0000060 K 0 0 0 0 7 r n K 0 0 0 0 8 r n
Комментарии:
1.
sort -rf "mapping file" working_file-1 | awk '$1==p{next} !$2{$2=0} {p=$1} 1' | tac > output.file
2. Есть ли какое-то значение в сочетании строчных и прописных букв K? Является ли совпадение чувствительным к регистру или без учета регистра?
3. @JonathanLeffler извини. это все верхние case..my опечатка.
4. Должны ли K00087, K00105, K00118, K01206 отображаться в выходных данных для показанных входов? Появится ли каждое число в
working_file-1
файле сопоставления? Оба входных файла расположены в порядке сортировки чисел Kxxxxx?5. @jhnc. да. извините. отредактировано сейчас
Ответ №1:
Учитывая файл «карта», такой как:
a
b
c
d
e
f
g
h
и файл «work1», такой как:
a A
c C
g G
и желаемый вывод «merged1», такой как:
a A
b
c C
d
e
f
g G
h
затем join
можно выполнить объединение:
join -1 1 -2 1 -a 1 -o 0,2.2 map work1 > merged1
-1 1 -2 1
присоединяется к первому (разделенному пробелами) полю каждого файла-a 1
печатает строки из первого файла, даже если они непарные-o 0,2.2
форматы вывода: поле соединения (первый столбец), разделитель (пробел), затем второе поле второго файла
Чтобы вместо этого создать «merged2», как:
a A
b 0
c C
d 0
e 0
f 0
g G
h 0
добавьте -e
опцию:
join -1 1 -2 1 -a 1 -e 0 -o 0,2.2 map work1 > merged2
Если в «work2» поля разделены символом, отличным от одного пробела, используйте эту -t
опцию.
Например, с «work2» с использованием одного разделителя табуляции, например:
a A
c C
g G
(примечание: stackoverflow отображает это с пробелами вместо одной вкладки), затем с помощью оболочки POSIX используйте -t ' '
(т. Е. ВКЛАДКА ЦИТАТА ЦИТАТА — может потребоваться ввести как: 'CTRL-VTAB'если оболочка выполняет завершение истории):
join -t ' ' -1 1 -2 1 -a 1 -e 0 -o 0,2.2 map work2 >merged3
или с помощью bash, -t $'t'
вместо этого возможно использование:
join -t
чтобы создать "merged3", как:
a A
b 0
c C
d 0
e 0
f 0
g G
h 0
(примечание: снова stackoverflow отображает вкладку в виде пробелов)
Комментарии:
1. Действительно спасибо, что так красиво все изложил. но почему-то это не сработало. с помощью join -1 1 -2 1 -a 1 -e 0 -o 0,2.2 работа с картой 1 > слияние2 вывод-K00001 K00002 K00003 .... с соединением -t $'t' -1 1 -2 1 -a 1 -e 0 -o 0,2.2 работа с картой 2 >>объединение3 вывод-K00001 0 K00002 0 K00003 0 .....
2. @Shail какую ОС вы используете? Возьмите ваши новые примеры из вашего вопроса и запустите команду join - это работает? Если нет, запустите
od -c work1; od -c map
новые файлы, которые вы только что создали, и добавьте выходные данные в свой вопрос. Если это работает, попробуйтеod -c realwork | less
или что-то в вашем реальном файле и проверьте, соответствует ли его формат тестовой версии.3. извините за поздний ответ. как-то не заметил этого. Я скопировал файл примера отсюда в новый файл и выполнил команду join (обе). видимо, это не сработало. я прикрепил выходные данные od-c work1; карта od-c выше. Я нахожусь на CentOS Linux 7
4. Похоже, что ваш файл содержит окончания строк в стиле DOS. Попробуйте установить
dos2unix
. Вы можете либо перезаписать исходные файлы напрямую (dos2unix file1 file2
), либо создать новые файлы (dos2unix -n in.file out.file
и т.д.). Затем выполнитеjoin
команду для новых файлов. После этого вам, возможно, потребуется запуститьunix2dos mergedfile
, чтобы сделать это также в формате DOS5. Спасибо. проблема решена. Действительно, это была проблема с форматом файла.
Ответ №2:
Использование GNU sort
для -s
(стабильной сортировки) это может быть то, что вам нужно:
$ sort -k1,1 -u -s working_file-1 mapping_file
K00001 0.188
K00002
K00003
K00004
K00005 15.97
K00006
K00007
K00008 188.09
или, если вы хотите добавить 0
s:
$ sort -k1,1 -u -s working_file-1 mapping_file |
awk -v OFS='t' '{print $1, $2 =0}'
K00001 0.188
K00002 0
K00003 0
K00004 0
K00005 15.97
K00006 0
K00007 0
K00008 188.09
Если у вас нет сортировки GNU, вы могли бы сделать:
$ sort -k1,1 -k2,2rn working_file-1 mapping_file |
awk -v OFS='t' '$1 != p{print $1, $2 0; p=$1}'
K00001 0.188
K00002 0
K00003 0
K00004 0
K00005 15.97
K00006 0
K00007 0
K00008 188.09
Комментарии:
1. Исправлено. Цель файла сопоставления состоит в том, что у меня есть куча рабочих файлов со случайными значениями K0 (все в диапазоне от K00001 до K25804). Некоторые из K0, присутствующих в одном рабочем файле, отсутствуют в другом. Я хочу присоединиться к этой группе рабочих файлов, добавив 0 к отсутствующим K0, чтобы получить единую таблицу.
2. мой Баш выдал ошибку "Изолированный символ в блоке: недопустимая спецификация блока "1,1 u"". при использовании sort-k1,1u-s working_file-1 сопоставление файла
3. Возможно
-k1,1u
, так и должно быть-k1,1 -u
. Хотя теоретически это может работать с любым типом POSIX , который имеет-s
, POSIX, похоже, не определяет, какая из нескольких "уникальных" строк будет напечатана. Версии GNU и FreeBSD, похоже, работают так, как ожидает Эд, но busybox все равно печатает обе строки (что, я думаю, может быть ошибкой).4. Вы не имеете
-s
в виду, что это для стабильного сорта?-u
предназначен для унификации - это то, что posix, похоже, не определяет, выбирая, какую "уникальную" строку выводить, когда они не идентичны (как в этом случае).5. кстати, информационная страница GNU coreutils подразумевает
-s
, что она избыточна при-u
использовании (и исходный код, похоже, согласен). в комментариях источника сбивчиво говорится как "Будет выведена только последняя из последовательности одинаковых строк", так и "выведите только первую из идентичной серии строк".
t' -1 1 -2 1 -a 1 -e 0 -o 0,2.2 map work2 >merged3
чтобы создать «merged3», как:
(примечание: снова stackoverflow отображает вкладку в виде пробелов)
Комментарии:
1. Действительно спасибо, что так красиво все изложил. но почему-то это не сработало. с помощью join -1 1 -2 1 -a 1 -e 0 -o 0,2.2 работа с картой 1 > слияние2 вывод-K00001 K00002 K00003 …. с соединением -t $’t’ -1 1 -2 1 -a 1 -e 0 -o 0,2.2 работа с картой 2 >>объединение3 вывод-K00001 0 K00002 0 K00003 0 …..
2. @Shail какую ОС вы используете? Возьмите ваши новые примеры из вашего вопроса и запустите команду join — это работает? Если нет, запустите
od -c work1; od -c map
новые файлы, которые вы только что создали, и добавьте выходные данные в свой вопрос. Если это работает, попробуйтеod -c realwork | less
или что-то в вашем реальном файле и проверьте, соответствует ли его формат тестовой версии.3. извините за поздний ответ. как-то не заметил этого. Я скопировал файл примера отсюда в новый файл и выполнил команду join (обе). видимо, это не сработало. я прикрепил выходные данные od-c work1; карта od-c выше. Я нахожусь на CentOS Linux 7
4. Похоже, что ваш файл содержит окончания строк в стиле DOS. Попробуйте установить
dos2unix
. Вы можете либо перезаписать исходные файлы напрямую (dos2unix file1 file2
), либо создать новые файлы (dos2unix -n in.file out.file
и т.д.). Затем выполнитеjoin
команду для новых файлов. После этого вам, возможно, потребуется запуститьunix2dos mergedfile
, чтобы сделать это также в формате DOS5. Спасибо. проблема решена. Действительно, это была проблема с форматом файла.
Ответ №2:
Использование GNU sort
для -s
(стабильной сортировки) это может быть то, что вам нужно:
или, если вы хотите добавить 0
s:
Если у вас нет сортировки GNU, вы могли бы сделать:
Комментарии:
1. Исправлено. Цель файла сопоставления состоит в том, что у меня есть куча рабочих файлов со случайными значениями K0 (все в диапазоне от K00001 до K25804). Некоторые из K0, присутствующих в одном рабочем файле, отсутствуют в другом. Я хочу присоединиться к этой группе рабочих файлов, добавив 0 к отсутствующим K0, чтобы получить единую таблицу.
2. мой Баш выдал ошибку «Изолированный символ в блоке: недопустимая спецификация блока «1,1 u»». при использовании sort-k1,1u-s working_file-1 сопоставление файла
3. Возможно
-k1,1u
, так и должно быть-k1,1 -u
. Хотя теоретически это может работать с любым типом POSIX , который имеет-s
, POSIX, похоже, не определяет, какая из нескольких «уникальных» строк будет напечатана. Версии GNU и FreeBSD, похоже, работают так, как ожидает Эд, но busybox все равно печатает обе строки (что, я думаю, может быть ошибкой).4. Вы не имеете
-s
в виду, что это для стабильного сорта?-u
предназначен для унификации — это то, что posix, похоже, не определяет, выбирая, какую «уникальную» строку выводить, когда они не идентичны (как в этом случае).5. кстати, информационная страница GNU coreutils подразумевает
-s
, что она избыточна при-u
использовании (и исходный код, похоже, согласен). в комментариях источника сбивчиво говорится как «Будет выведена только последняя из последовательности одинаковых строк», так и «выведите только первую из идентичной серии строк».