Есть ли функция Bash, которая позволяет мне отделить / удалить / изолировать строку из файла, когда они имеют одно и то же первое слово - PullRequest
1 голос
/ 11 июля 2019

У меня есть текстовый файл, подобный этому:

id ; lorem ipsum  fgdg df gdg
id ; lorem ipsum  fgdg df gdg
id ; lorem ipsum  fgdg df gdg
id ; lorem ipsum  fgdg df gdg
id ; lorem ipsum  fgdg df gdg

И если 2 идентификатора похожи, я хочу отделить строку, где 2 идентификатора похожи, и строку, которые являются уникальными.

uniquefile содержит строки с уникальным идентификатором.notuniquefile содержит строки, в которых их нет.

Я уже нашел способ почти сделать это, но только с первым словом.По сути, это просто изоляция идентификатора и удаление остатка строки.

Команда 1: изоляция уникального идентификатора (но отсутствует строка):

awk -F ";" '{!seen[$1]++};END{for(i in seen) if(seen[i]==1)print i }' originfile >> uniquefile

Команда 2: изоляция неуникального идентификатора(но пропуская строку и теряя содержимое «lorem ipsum», которое может быть различным в зависимости от строки):

awk -F ":" '{!seen[$1]++;!ligne$0};END{for(i in seen) if(seen[i]>1)print i  }' originfile >> notuniquefile

Итак, в идеальном мире я хотел бы, чтобы вы помогли мне получить такой результат:

originfile:

1 ; toto
2 ; toto
3 ; toto
3 ; titi
4 ; titi

uniquefile:

1 ; toto
2 ; toto
4 ; titi

notuniquefile:

3 ; toto
3 ; titi

Хорошего дня.

Ответы [ 4 ]

0 голосов
/ 12 июля 2019

Еще один метод с двумя командами unix, который работает, если ваши поля id всегда имеют одинаковую длину (предположим, что они имеют длину одного символа, как в моих тестовых данных, но, конечно, он работает и для более длинных полей):

# feed the testfile.txt sorted to uniq
# -w means: only compare the first 1 character of each line
# -D means: output only duplicate lines (fully not just one per group)
sort testfile.txt | uniq -w 1 -D > duplicates.txt

# then filter out all duplicate lines from the text file
# to just let the unique files slip through
# -v means: negate the pattern
# -F means: use fixed strings instead of regex
# -f means: load the patterns from a file
grep -v -F -f duplicates.txt testfile.txt > unique.txt

И вывод (для тех же строк ввода, что и в моем другом посте):

$uniq -w 2 -D  testfile.txt 
2;line B
2;line C
3;line D
3;line E
3;line F

и

$ grep -v -F -f duplicates.txt testfile.txt 
1;line A
4;line G

Btw. в случае, если вы хотите избежать grep, вы также можете сохранить выходные данные сортировки (скажем, в sorted_file.txt) и заменить вторую строку на

uniq -w 1 -u sorted_file.txt > unique.txt

где число за -w снова является длиной вашего поля id в символах.

0 голосов
/ 11 июля 2019

не проверено: обработать файл дважды: сначала посчитать идентификаторы, затем решить, где распечатать запись:

awk -F';' '
    NR == FNR      {count[$1]++; next}
    count[$1] == 1 {print > "uniquefile"}
    count[$1]  > 1 {print > "nonuniquefile"}
' file file
0 голосов
/ 12 июля 2019

С помощью чистого bash-скрипта вы можете сделать это так:

duplicate_file="duplicates.txt"
unique_file="unique.txt"
file="${unique_file}"
rm $duplicate_file $unique_file
last_id=""
cat testfile.txt | sort | ( 
    while IFS=";" read id line ; do
      echo $id
      if [[ "${last_id}" != "" ]] ; then
          if [[ "${last_id}" != "${id}" ]] ; then
             echo "${last_id};${last_line}" >> "${file}"
             file="${unique_file}"
          else
             file="${duplicate_file}"
             echo "${last_id};${last_line}" >> "${file}"
          fi
      fi
      last_line="${line}"
      last_id="${id}"
    done
    echo "${last_id};${last_line}" >> "${file}"
)

С входным файлом как:

1;line A
2;line B
2;line C
3;line D
3;line E
3;line F
4;line G

Это выводит:

$ cat duplicates.txt 
2;line B
2;line C
3;line D
3;line E
3;line F
work$ cat unique.txt 
1;line A
4;line G
0 голосов
/ 11 июля 2019

Вот небольшой скрипт на Python, который делает это:

#!/usr/bin/env python3

import sys

unique_markers = []
unique_lines = []
nonunique_markers = set()
for line in sys.stdin:
  marker = line.split(' ')[0]
  if marker in nonunique_markers:
    # found a line which is not unique
    print(line, end='', file=sys.stderr)
  elif marker in unique_markers:
    # found a double
    index = unique_markers.index(marker)
    print(unique_lines[index], end='', file=sys.stderr)
    print(line, end='', file=sys.stderr)
    del unique_markers[index]
    del unique_lines[index]
    nonunique_markers.add(marker)
  else:
    # marker not known yet
    unique_markers.append(marker)
    unique_lines.append(line)
for line in unique_lines:
  print(line, end='', file=sys.stdout)

Это не просто решение оболочки (которое было бы громоздким и сложным в обслуживании, IMHO), но, возможно, оно поможет вам.

Назовите это так:

separate_uniq.py < original.txt > uniq.txt 2> nonuniq.txt

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...