Пересечение двух списков в Bash

Я пытаюсь написать простой script, который отобразит содержимое, содержащееся в двух списках. Чтобы упростить, позвольте использовать ls в качестве примера. Представьте, что "один" и "два" - это каталоги.

one=`ls one`
two=`ls two`
intersection $one $two

Я все еще довольно зеленый в bash, поэтому не стесняйтесь исправить то, как я это делаю. Мне просто нужна команда, которая будет распечатывать все файлы в "одном" и "двух". Они должны существовать в обоих. Вы можете назвать это "пересечением" между "одним" и "двумя".

Ответ 1

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

Ответ 2

Используйте команду comm:

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

"сортировка" на самом деле не нужна, но я всегда включаю ее, прежде чем использовать "comm" на всякий случай.

Ответ 3

Решение с comm

comm отлично, но нужно работать с отсортированным списком. И, к счастью, здесь мы используем ls, который из ls Bash man page

Сортировка записей в алфавитном порядке, если ни один из -cftuSUX или --sort.

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

Альтернатива с sort

Пересечение двух списков:

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

симметричная разность двух списков:

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

Bonus

Играйте с ним;)

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

Ответ 4

Менее эффективная (чем комм) альтернатива:

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

Ответ 5

Соединение - это еще один хороший вариант в зависимости от ввода и желаемого вывода

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

Ответ 6

Есть еще один вопрос о 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" отвечает номерам; следовательно, использование "sort" и "sort -g".