Отображение двух файлов рядом

Как два несортированных текстовых файла разной длины могут отображаться рядом друг с другом (в столбцах) в shell

Учитывая one.txt и two.txt:

$ cat one.txt
apple
pear
longer line than the last two
last line

$ cat two.txt
The quick brown fox..
foo
bar 
linux

skipped a line

Отображать:

apple                               The quick brown fox..
pear                                foo
longer line than the last two       bar 
last line                           linux

                                    skipped a line

paste one.txt two.txt почти делает свое дело, но не выравнивает столбцы должным образом, так как просто печатает одну вкладку между столбцами 1 и 2. Я знаю, как это сделать с помощью emacs и vim, но хочу, чтобы вывод выводился на стандартный вывод для передачи по конвейеру и т. д.

Решение, которое я придумал, использует sdiff, а затем передает в sed, чтобы удалить вывод sdiff добавляет.

sdiff one.txt two.txt | sed -r 's/[<>|]//;s/(\t){3}//'

Я мог бы создать функцию и вставить ее в свой .bashrc, но наверняка уже существует команда для этого (или потенциально более чистое решение)?


person Chris Seymour    schedule 12.11.2012    source источник
comment
Не в оболочке, но стоит упомянуть: используйте meld!   -  person fedorqui 'SO stop harming'    schedule 28.09.2016


Ответы (9)


Вы можете использовать pr для этого, используя флаг -m для объединения файлов, по одному на столбец, и -t для пропуска заголовков, например.

pr -m -t one.txt two.txt

выходы:

apple                               The quick brown fox..
pear                                foo
longer line than the last two       bar
last line                           linux

                                    skipped a line

Смотрите также:

person Hasturkun    schedule 12.11.2012
comment
Идеально! Знал, что что-то будет, никогда раньше не слышал о pr. Я пробовал с 3 файлами, и вывод был усечен, но опция -w решила эту проблему. Хороший ответ. - person Chris Seymour; 12.11.2012
comment
@sudo_o: рад помочь, coreutils полон драгоценных камней - person Hasturkun; 12.11.2012
comment
Есть ли способ для pr автоматически определять ширину экрана? - person Matt; 11.04.2014
comment
@Matt: Вы можете использовать $COLUMNS, который должен быть предоставлен оболочкой. - person Hasturkun; 11.08.2014
comment
При использовании для печати двух файлов рядом pr обрезает конец длинных строк. Есть ли способ заставить его обернуть строки? - person molnarg; 08.04.2015
comment
@molnarg: Один из способов состоит в том, чтобы сначала свернуть каждый входной файл до половины ширины страницы, за вычетом ширины разделителя столбцов. например, в bash: pr -t -m -w $PAGE_WIDTH <(fold -w $HALF_PAGE_WIDTH one.txt) <(fold -w $HALF_PAGE_WIDTH two.txt). Это можно элегантно решить в пользовательском скрипте. - person crw; 23.06.2017
comment
Есть ли способ показать 1 строку из первого файла и 10 строк из второго файла? Его результаты машинного перевода, которые я хочу просмотреть рядом. - person Ashutosh Baheti; 30.01.2018
comment
pr -mtJ ... чтобы использовать всю доступную ширину. - person Lichtgestalt; 17.07.2020
comment
могу ли я применить это для вывода двух процессов вместо файла? - person alper; 06.11.2020

Чтобы немного расширить ответ @Hasturkun: по умолчанию pr использует только 72 столбца для вывода, но это относительно просто чтобы он использовал все доступные столбцы окна вашего терминала:

pr -w $COLUMNS -m -t one.txt two.txt

Большинство оболочек будут хранить (и обновлять) ширину экрана вашего терминала в переменной среды $COLUMNS, поэтому мы просто передаем это значение в pr, чтобы использовать его для настройки ширины вывода.

Это также отвечает на вопрос @Matt:

Есть ли способ для pr автоматически определять ширину экрана?

Итак, нет: сам pr не может определить ширину экрана, но мы немного помогаем, передавая ширину терминала через параметр -w.

person pvandenberk    schedule 08.05.2014

Если вы знаете, что во входных файлах нет вкладок, то использование expand упрощает @oyss ответ:

paste one.txt two.txt | expand --tabs=50

Если во входных файлах могут быть вкладки, вы всегда можете сначала развернуть:

paste <(expand one.txt) <(expand two.txt) | expand --tabs=50
person Bob    schedule 25.08.2015

paste one.txt two.txt | awk -F'\t' '{
    if (length($1)>max1) {max1=length($1)};
    col1[NR] = $1; col2[NR] = $2 }
    END {for (i = 1; i<=NR; i++) {printf ("%-*s     %s\n", max1, col1[i], col2[i])}
}'

Использование * в спецификации формата позволяет динамически указывать длину поля.

person Barmar    schedule 12.11.2012

Есть sed способ:

f1width=$(wc -L <one.txt)
f1blank="$(printf "%${f1width}s" "")"
paste one.txt two.txt |
    sed "
        s/^\(.*\)\t/\1$f1blank\t/;
        s/^\(.\{$f1width\}\) *\t/\1 /;
    "

В разделе bash вы можете использовать printf -v:

f1width=$(wc -L <one.txt)
printf -v f1blank "%${f1width}s"
paste one.txt two.txt |
    sed "s/^\(.*\)\t/\1$f1blank\t/;
         s/^\(.\{$f1width\}\) *\t/\1 /;"

(Конечно, решение @Hasturkun pr является самым точным!):

Преимущество sed перед pr

Вы можете точно выбрать ширину разделения и/или разделители:

f1width=$(wc -L <one.txt)
(( f1width += 4 ))         # Adding 4 spaces
printf -v f1blank "%${f1width}s"
paste one.txt two.txt |
    sed "s/^\(.*\)\t/\1$f1blank\t/;
         s/^\(.\{$f1width\}\) *\t/\1 /;"

Или, например, пометить строки, содержащие line:

f1width=$(wc -L <one.txt)
printf -v f1blank "%${f1width}s"
paste one.txt two.txt |
    sed "s/^\(.*\)\t/\1$f1blank\t/;
  /line/{s/^\(.\{$f1width\}\) *\t/\1 |ln| /;ba};
         s/^\(.\{$f1width\}\) *\t/\1 |  | /;:a"

будет отображать:

apple                         |  | The quick brown fox..
pear                          |  | foo
longer line than the last two |ln| bar 
last line                     |ln| linux
                              |  | 
                              |ln| skipped a line
person F. Hauri    schedule 04.01.2013
comment
bash f1width=$(wc -L <one.txt) printf -v f1blank "%${f1width}s" paste one.txt two.txt | sed "s/^\(.*\)\t/\1$f1blank\t/; /line/{s/^\(.\{$f1width\}\) *\t/\1 |ln| /;ba}; s/^\(.\{$f1width\}\) *\t/\1 | | /;:a" Хорошее решение!! действительно полезно в других контекстах - person Jishnu P Das; 10.03.2021

удаление динамического подсчета длины поля из ответа Бармара сделает его намного короче команды ... но вам все равно нужен хотя бы один скрипт для завершения работы, которого нельзя избежать независимо от того, какой метод вы выберете.

paste one.txt two.txt |awk -F'\t' '{printf("%-50s %s\n",$1,$2)}'
person oyss    schedule 12.11.2012

Если вы хотите узнать реальную разницу между двумя файлами, расположенными рядом, используйте diff -y:

diff -y file1.cf file2.cf

Вы также можете установить ширину вывода, используя параметр -W, --width=NUM:

diff -y -W 150 file1.cf file2.cf

и чтобы вывод столбца diff соответствовал вашему текущему окну терминала:

diff -y -W $COLUMNS file1.cf file2.cf
person user3498040    schedule 12.01.2015

Найдите ниже решение на основе Python.

import sys

# Specify the number of spaces between the columns
S = 4

# Read the first file
l0 = open( sys.argv[1] ).read().split('\n')

# Read the second file
l1 = open( sys.argv[2] ).read().split('\n')

# Find the length of the longest line of the first file
n = len(max(l0, key=len))

# Print the lines
for i in  xrange( max( len(l0), len(l1) ) ):

    try:
        print l0[i] + ' '*( n - len(l0[i]) + S) + l1[i]
    except:
        try:
            print ' ' + ' '*( n - 1 + S) + l1[i]
        except:
            print l0[i]

Пример

apple                            The quick brown fox..
pear                             foo
longer line than the last two    bar 
last line                        linux

                                 skipped a line
person funk    schedule 29.01.2016

person    schedule
comment
sdiff - это diff -y, о котором я говорю в вопросе. - person Chris Seymour; 01.01.2014
comment
Да, верно ... было упомянуто, чтобы показать другую настройку команды / флага для этого. - person Vikas Jain; 02.01.2014
comment
Но это не отвечает на вопросы diff добавляет символы между двумя файлами. - person Chris Seymour; 02.01.2014