Bash에서 두 목록의 교차


163

두 목록에있는 내용을 나열하는 간단한 스크립트를 작성하려고합니다. 단순화하기 위해 ls를 예로 들어 봅시다. "1"과 "2"가 디렉토리라고 상상해보십시오.

하나 =`하나 하나`
둘 =`ls 둘`
교차로 $ 1 $ 2

나는 여전히 bash에서 상당히 녹색이므로, 내가하는 일을 자유롭게 수정하십시오. "1"과 "2"의 모든 파일을 출력하는 명령이 필요합니다. 둘 다 존재해야합니다. 이것을 "1"과 "2"사이의 "교차"라고 부를 수 있습니다.


실제로 Bash 스크립트에서 두 변수 를 교차시키는 방법에 대한 답은 없습니다 .
jameshfisher

제 생각에는 새로운 질문 인 것 같습니다. 그 질문에 대한 답은 여기에 있습니다.
Jean-Christophe Meillaud

논란의 여지는 있지만 더 유용한 방법은 거의 중복에 stackoverflow.com/questions/2312762/...
tripleee

답변:


285
comm -12  <(ls 1) <(ls 2)

37
comm오늘까지 내가 알지 못했다고 믿을 수 없다 . 이 방금 내 주 전체를 만들었습니다 :)
Darragh Enright

22
comm입력을 정렬해야합니다. 이 경우 ls출력을 자동으로 정렬하지만 다른 용도로 수행해야 할 수도 있습니다.comm -12 <(some-command | sort) <(some-other-command | sort)
Alexander Bird

11
ls '출력을 사용하지 마십시오. ls는 디렉토리 메타 데이터를 대화식으로 볼 수있는 도구입니다. 코드로 ls의 출력을 구문 분석하려는 시도가 중단됩니다. 글롭은 훨씬 간단하고 정확합니다 :``* .txt의 파일 ''. mywiki.wooledge.org/ParsingLs
Rany Albeg Wein

2
방금 특성과 함께 제공되는 public방법의 사용법을 찾기 위해 이것을 사용 했습니다. 나는 달렸고 , 운 좋게도 특성이 포함 된 파일의 이름으로 끝났습니다. error()git grep$ comm -12 <(git grep -il "\$this->error(" -- "*.php") <(git grep -il "Dash_Api_Json_Response" -- "*.php")
localheinz

3
재밌 네요. 나는 awk로 미친 것들을하려고했습니다.
Rolf

55

솔루션 comm

comm훌륭하지만 실제로 정렬 된 목록으로 작업해야합니다. 그리고 다행히도 여기서 우리 lslsBash 맨 페이지 에서 어떤 것을 사용 합니다

-cftuSUX 또는 --sort가 없으면 알파벳순으로 항목을 정렬합니다.

comm -12  <(ls one) <(ls two)

와 대안 sort

두 목록의 교차점 :

sort <(ls one) <(ls two) | uniq -d

두 목록의 대칭 적 차이 :

sort <(ls one) <(ls two) | uniq -u

보너스

그것으로 플레이;)

cd $(mktemp -d) && mkdir {one,two} && touch {one,two}/file_{1,2}{0..9} && touch two/file_3{0..9}

2
보완 대신에 나는 그것이 일반적으로 대칭 적 차이 라고 생각합니다 .
앤드류 나사로

29

다음 comm명령을 사용하십시오 .

ls one | sort > /tmp/one_list
ls two | sort > /tmp/two_list
comm -12 /tmp/one_list /tmp/two_list

"정렬"은 실제로 필요하지는 않지만, 항상 "comm"을 사용하기 전에 포함시킵니다.


5
정렬이 필요하기 때문에 포함하는 것이 좋으며 예제로는 ls 만 사용했습니다.
Thor84no

3

덜 효율적인 (comm보다) 대안 :

cat <(ls 1 | sort -u) <(ls 2 | sort -u) | uniq -d

1
스크립트에서 데비안의 / bin / dash 또는 다른 비배시 쉘을 사용하는 경우 괄호를 사용하여 명령 출력을 연결할 수 있습니다 (ls 1; ls 2) | sort -u | uniq -d.
질소

1
@ MikaëlMayer 답장을 보낸 사람의 이름을 표시해야합니다. 그렇지 않으면 내 말이 맞는 것으로 간주됩니다.
Benubird

@nitrogen MikaëlMayer는 정확합니다-uniq sort -u | uniq -d가 그들을 찾기 전에 정렬이 중복을 제거했기 때문에 체인 은 아무것도하지 않습니다. 내 명령이 무엇인지 이해하지 못했다고 생각합니다.
Benubird

@Benubird 나는 당신의 명령 cat <(ls 1 | sort -u) <(ls 2 | sort -u) | uniq -d으로 아무것도 출력 하지 못했습니다 . 내 명령은 을 표시 (ls 1; ls 2) | sort | uniq -d하지 않고 -u목록 교차를 표시 해야 합니다. @ MikaëlMayer는 내 원래 명령이 깨 졌다는 것이 옳았습니다.
질소

@nitrogen cat을 사용하는 이유는 이것이 일반적인 솔루션이기 때문에 ls다른 것과 같이 대체 할 수 있기 때문 find입니다. 명령 중 하나가 두 줄을 동일하게 반환하면 복제본으로 선택하기 때문에 솔루션에서이를 허용하지 않습니다. 사용자가 ls 1/*하위 디렉토리의 모든 파일 을 수행 하고 비교 하려는 경우에도 작동합니다 . 그렇지 않으면 그렇습니다. 내 배쉬에 따라 다를 수 있습니다.
Benubird

2

입력과 원하는 출력에 따라 조인이 또 다른 좋은 옵션입니다.

join -j1 -a1 <(ls 1) <(ls 2)

-1

또 다른 Stackoverflow 질문 "bash의 배열 교차"가 중복으로 표시됩니다. 내 의견으로는 그 질문은 두 개의 bash 배열을 비교하는 것에 대해 이야기하지만이 질문은 bash 파일에 중점을두기 때문에 상당히 동일하지 않습니다. 현재 종료 된 다른 질문에 대한 한 줄 답변은 다음과 같습니다.

# List1=( 0 1 2 3 4   6 7 8 9 10 11 12)
# List2=(   1 2 3   5 6   8 9    11 )
# List3=($(comm -12 <(echo ${List1[*]}| tr " " "\n"| sort) <(echo ${List2[*]} | tr " " "\n"| sort)| sort -g))
# echo ${List3[*]}
1 2 3 6 8 9 11

comm 유틸리티는 영숫자 정렬을 수행하는 반면 "bash의 배열 교차"는 숫자를 사용합니다. 따라서 "정렬"및 "정렬 -g"사용법.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.