구분된 필드 비교

구분된 필드 비교

내 파일에는 학생과 교사라는 두 개의 필드가 있습니다. 세미콜론으로 구분되어 있으며 어떤 학생에게 두 명의 다른 교사가 있는지 찾고 싶습니다.

jdoe;ateacher
jdoe;bteacher
jsmith;cteacher
bbrown;dteacher
dholden;eteacher

다음 주소로 전송됩니다:

jdoe;ateacher
jdoe;bteacher

쉘로 어떻게 할 수 있나요?

노트:이것은 숙제입니다. 정확한 답변을 찾고 있는 것이 아니라 어디서부터 시작해야 할지 모르겠습니다. 파일에서 필요한 필드로 구문 분석하고 전송했습니다. 이제 중복 항목을 찾으면 되지만 시작하는 방법을 모르겠습니다.

답변1

표시하는 파일 형식이 엄격하여 학생에게 교사가 2명인 경우 학생이 두 번만 표시되고 특정 학생의 항목이 항상 서로 옆에 있다고 가정하면 이 명령을 사용하여 모든 중복 항목을 찾을 수 있습니다. 이 파일의 중복은 학생에게 교사가 여러 명 있다는 것을 나타내므로 이 사실을 무시할 수 있습니다.

$ awk -F';' '{ print $1 }' file | uniq -d
jdoe

그러면 파일이 구문 분석되고 필드 구분 기호 스위치를 file사용하여 awk분할됩니다 -F';'. 그런 다음 awk학생의 이름인 첫 번째 필드만 인쇄하도록 지시합니다 . 그런 다음 해당 출력을 파이프 uniq하고 중복된 줄만 인쇄하도록 지시합니다.

그런 다음 for 루프에서 이 정보를 사용하고 위 명령으로 반환된 목록에 학생이 포함된 행만 인쇄할 수 있습니다. 루프의 대략적인 구조는 다음과 같습니다.

$ for i in $(..cmd from above..); do 
    ... print lines that contain "$i" ...
done

여기서는 초기 명령의 출력을 가져와서 awkBash 셸의 for 루프를 사용하여 반복합니다. 이는 일반적으로 대부분의 사람들이 처음 시작할 때 취하는 접근 방식입니다.

$ for i in $(awk -F';' '{ print $1 }' file | uniq -d); do \
    grep "^$i;" file; done
jdoe;ateacher
jdoe;bteacher

이 방법은 효과적이지만 몇 가지 문제점도 있습니다. 파일 이름에 공백이 포함되어 있으면 이 방법은 실패합니다. while 루프를 사용하여 보다 복잡한 접근 방식으로 전환할 수 있습니다.

$ while read; do grep "^$i;" file; done \
    < <(awk -F';' '{ print $1 }' file | uniq -d)
jdoe;ateacher
jdoe;bteacher

여기서는 명령의 출력을 가져와서 아래와 같이 while 루프에 전달합니다.

$ while read; do .... ; done < <(...our command...)

이것의 장점은 이 표기법을 사용하여 임시 파일을 만들고 모든 결과를 while 루프에 줄로 전달할 수 있다는 것입니다. 따라서 이 read명령은 이제 for 루프 구현에서 공백이 아닌 줄 바꿈으로 구분된 결과만 구문 분석합니다.

< <(...command...)

for 루프와 공백을 사용하면 다음과 같은 일이 발생합니다.

$ for i in jdoe john smith jjill;do echo "$i"; done
jdoe
john
smith
jjill

관련 정보