행에서 고유하게 정렬

행에서 고유하게 정렬

한 줄이나 행에서 고유하게 정렬할 수 있는 방법을 제안해 주시겠습니까? 다음과 같은 정보가 있습니다.

Special   c1,c2,c5,c7,c1,c2   
Special2  C6

Special( 와 사이에 TAB 문자가 있습니다 c1...).

나는 다음과 같은 출력을 원합니다 :

Special   c1,c2,c5,c7  
Special2  C6

이 작업을 어떻게 수행할 수 있나요?

답변1

사용이 답변,

perl -MList::MoreUtils=uniq -laF'\t' -ne '
    $F[1] = join(",", uniq(sort(split(",", $F[1])))); print join("\t", @F)'

이는 외부 패키지에 따라 다릅니다.목록::더보기Utils. 외부 종속성을 설치하지 않으려면 기능을 다시 구현하는 uniq것이 좋습니다.몇 줄만 더 Perl을 작성하면 됩니다.. (macOS에서는 기본 시스템의 일부로 설치한 것 같습니다.)

답변2

perl -F'\t|,' -lane 'my %h; print shift @F, "\t", join ",", sort grep !$h{$_}++, @F' dataf

설명

  • -F'\t|,'=> 각 레코드 필드를 또는 문자 @F의 배열로 분할합니다 .TABcomma
  • -lRSto newlineORSto 도 설정합니다 newline.
  • -aFS가 선택한 항목에 따라 각 레코드를 단어로 자동 분할합니다 -F.
  • -n입력에 대한 루프에서 암시적 레코드 읽기를 설정하고 AND요청한 경우에만 내용을 인쇄합니다.
  • -e위에서 선택한 항목을 Perl기반으로 입력의 각 레코드에 대해 실행되는 코드 입니다 .RS-l
  • 첫 번째 요소는 로 제공되고 shift나머지 요소는 uniquified해시의 키로 저장되어 %h레코드를 읽을 때마다 재생성됩니다. 그런 다음 고유 요소가 정렬되어 쉼표로 결합되어 인쇄됩니다.

답변3

OpenBSD awk, GNU awk및 다음으로 테스트되었습니다 mawk.

awk -F ',| +' '{ for (i = 2; i <= NF; ++i) { print $1, $i } }' data.in |
sort -u |
awk '{ f[$1] = (f[$1] ? f[$1] "," : "") $2 } END { for (k in f) { print k, f[k] } }'

첫 번째는 awk주어진 데이터를 다음으로 확장합니다.

Special c1
Special c2
Special c5
Special c7
Special c1
Special c2
Special2 C6

쉼표와 여러 공백을 필드 구분 기호로 사용하고, 입력의 각 레코드(줄)에 대해 첫 번째 필드를 인쇄한 다음 다른 각 필드를 차례로 별도의 줄에 인쇄합니다. 이는 구분 기호로 적절하게 해석되는 위치 외에 줄에 다른 공백이나 쉼표가 없다고 가정합니다.

중간 sort에 정렬이 되어있어요

Special2 C6
Special c1
Special c2
Special c5
Special c7

전체 줄을 정렬 키로 사용하여 정렬을 수행하고 중복된 줄을 삭제합니다.

마지막은 awk데이터를 다음과 같이 재결합합니다.

Special c1,c2,c5,c7
Special2 C6

첫 번째 필드를 연관 배열의 키로 사용하고 두 번째 필드에 해당 데이터를 쉼표로 구분하여 연결하여 값으로 저장합니다. 마지막에는 수집된 모든 데이터가 인쇄됩니다.

답변4

한 줄로 다른 방법:

while read line; do echo "$line" | awk '{print $1}' | tr '\n' ' ';  echo "$line" | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ',' | sed -e 's/.$//g'; echo; done < file_to_sort

모든 줄의 첫 번째 열( echo $line | awk '{print $1}' | tr '\n' ' ';)을 가져와 적용하기 위해 단일 열로 변환한 후 ','로 구분된 두 번째 열 값을 정렬한 다음 sort원래 형식( echo $line | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ',')을 사용하여 다시 단일 행으로 변환합니다.

@tripleee가 제안한 대로 줄 분할 수행:

while IFS=$'\t' read first second; do printf "%s\t%s\n" "$first" "$(tr ',' '\n' <<<"$second" | sort | tr '\n' ',' | sed -e 's/.$//g';)"; done < file_to_sort

관련 정보