Сортировка -u (или сортировка | uniq )для пары столбцов, но сохранить информацию в третьем столбце и добавить ее в сохраненную строку?

Предлагаю вам воспользоваться моим новым инструментом websocat .

echo "Some data to be sent" | websocat ws://server/url

Очевидно, что существуют также альтернативы, такие как wscat (golang)или wscat (node).

3
26.08.2020, 05:00
3 ответа

Я не знаю, как это сделать, используя только sort,но вы можете «свернуть» значения, например, с помощью awk, а затем отсортировать:

$ awk -F'\t' '
    BEGIN{OFS=FS} 
    {k = $1 FS $2} 
    {a[k] = a[k] == "" ? $3 : a[k] "," $3} 
    END{for (k in a) print k,a[k]}
 ' file | sort
a       b       hello,goodbye
a       c       I say
g       g       test

В последней версии GNU awk вы можете избежать внешней сортировки, установив порядок обхода массива с помощьюPROCINFO:

awk -F'\t' '
  BEGIN{OFS=FS} 
  {k = $1 FS $2} 
  {a[k] = a[k] == "" ? $3 : a[k] "," $3} 
  END{PROCINFO["sorted_in"]="@ind_str_asc"; for (k in a) print k,a[k]}
' file

В качестве альтернативы, с помощью массива данных GNU

datamash groupby 1,2 collapse 3 <file

или более подробно (, но более гибко )с Миллером

mlr --nidx --fs tab nest --implode --values --across-records --nested-fs, -f 3  file
3
18.03.2021, 23:09

Двухэтапное -решение в bash, использующее временные файлы:

$ cat table.csv
a       b       hello
a       b       goodbye
g       g       test
a       c       I say

$ WD=$(mktemp -d) ; while read K1 K2 V ; do echo -n ",$V" >>$WD/$K1:$K2 ; done <table.csv

$ sort -k1,1 -k2,2 -u table.csv | while read K1 K2 V ; do echo $K1 $K2 $(sed 's/^.//' <$WD/$K1:$K2) ; done
a b hello,goodbye
a c I say
g g test

Суть этого решения заключается в использовании перенаправления добавления в оболочке(>>)для сбора значений для ключей, которые равны перед сортировкой.

0
18.03.2021, 23:09

Это также можно сделать с помощью sedфункции (извините, это не совсем по-человечески -читабельно):

echo "a      b       hello
a       c       goodbye
g       g       foo
a       c       bar
a       b       test
a       c       I say" | sort -k1,1 -k2,2 | sed ":a N; s/\([^\t]*\)\t\([^\t]*\)\t\([^\t]*\)\n\1\t\2\t\([^\t]*\)/\1\t\2\t\3,\4/; ta; P; D; ba;"

И вывод, как и ожидалось:

a       b       hello,test
a       c       bar,goodbye,I say
g       g       foo
  • сначала отсортируйте, затем используйте sedвместо uniq.
  • N;попросит sedработать на 2-х строках (или «еще одну строку» )вместо 1.
  • s/.../.../объединит две строки.
    • \([^\t]*\)займет столбец (как можно больше символов, но не\t).
    • \t— разделитель табуляции ().
    • \n\t\1\t\2\tпроверяет, есть ли у нас вторая строка с двумя похожими первыми столбцами.
    • /\1\t\2\t\3,\4/преобразует 2 строки в одну с одинаковыми первым и вторым столбцами, а третий столбец объединяется.
  • :a... ta;похоже на цикл while(сделать это снова, пока sзамена работала ).
  • P; D;если мы здесь, то sне удалось, поэтому у нас есть две «разные» (в первой или второй колонке )строк в пространстве шаблонов. Pпечатает первую строку (с возможными объединенными строками ), а Dудаляет строку, которую мы напечатали.
  • ba;зацикливается, пока он может читать строки (с 1 строкой в ​​пространстве шаблонов ).
0
18.03.2021, 23:09

Теги

Похожие вопросы