объедините текстовые файлы по столбцам

Использовать

your_command | wc -l

Из руководства:

NAME
       wc - print newline, word, and byte counts for each file

...

       -l, --lines
          print the newline counts
54
22.05.2015, 16:17
7 ответов

Вам просто нужно column команда, и говорит этому использовать вкладки для разделения столбцов

paste file1 file2 | column -s $'\t' -t

Для обращения к противоречию "пустой ячейки" нам просто нужно -n опция к column:

$ paste <(echo foo; echo; echo barbarbar) <(seq 3) | column -s $'\t' -t
foo        1
2
barbarbar  3

$ paste <(echo foo; echo; echo barbarbar) <(seq 3) | column -s $'\t' -tn
foo        1
           2
barbarbar  3

Моя страница справочника столбца указывает -n "расширение GNU/Linux Debian". Моя система Fedora не показывает проблему пустой ячейки: это, кажется, получено из BSD, и в странице справочника говорится, что "Версия 2.23 изменила-s опцию быть нежадной"

70
27.01.2020, 19:33
  • 1
    glenn: Вы - герой часа! Я знал, что вокруг было что-то вроде этого, но я не мог rememeber это. Я скрывался по этому вопросу; ожидание Вас :)... column, конечно; как очевидный (задним числом) +1... Спасибо... –  Peter.O 11.07.2011, 18:58
  • 2
    я только что заметил это column -s $'\t' -t игнорирует пустые ячейки, приводящие ко всем последующим ячейкам направо от него (на той строке) к перемещенному налево; т.е., в результате пустой строки в файле или этом являющийся короче... :( –  Peter.O 13.07.2011, 07:08
  • 3
    @masi, исправленный –  glenn jackman 03.11.2016, 12:40
  • 4
    n не работает в RHEL. Существует ли альтернатива? –  Koshur 14.07.2017, 09:20

Вы ищете удобного денди pr команда:

paste file1 file2 | pr -t -e24

"-e24", "разворачивают позиции табуляции до 24 пробелов". К счастью, paste помещает символ табуляции между столбцами, таким образом, pr может развернуть его. Я выбрал 24 путем подсчета символов в "Рекурсивно перечислимом" и добавления 2.

12
27.01.2020, 19:33
  • 1
    Спасибо!, Что действительно "разворачивает позиции табуляции до 24 пробелов", средних? –  StackExchange for All 11.07.2011, 04:53
  • 2
    , который я также обновляю с примером, где Ваш метод почти закрепляет его кроме небольшого неточного совмещения. –  StackExchange for All 11.07.2011, 05:08
  • 3
    Традиционно "позиции табуляции" поражают каждые 8 пробелов. "123TABabc" распечатать с символ 8 ширины символов от запуска строки. Установка его к 24 поместила бы в 24 символьных ширины от запуска строки. –  Bruce Ediger 11.07.2011, 07:20
  • 4
    Вы говорите, что "-e24", "разворачивают позиции табуляции до 24 пробелов", итак, почему бы не использовать expand управляйте непосредственно: paste file1 file2 | expand -t 24 ? –  WhiteWinterWolf 13.09.2016, 11:48
  • 5
    @Masi - мой ответ подобен, но менее сложен что ответ @techno ниже. Это не вызывает sed таким образом, существует один процесс, который не работает. Это использует pr который является древней командой, датируясь ко дням Unix SysV, я думаю, таким образом, она могла бы существовать на большем количестве установок, чем expand. Это - просто старая школа, короче говоря. –  Bruce Ediger 03.11.2016, 18:05

Обновление: Здесь ia намного более простой сценарий (что тот в конце вопроса) для сведенного в таблицу вывода. Просто передайте имя файла ему, как Вы были бы к paste... Это использует html сделать кадр, таким образом, это tweakable. Это действительно сохраняет несколько пробелов, и выравнивание столбца сохраняется, когда это встречается с unicode символами. Однако путем редактор или рендереры средства просмотра unicode является другой вопрос полностью...

┌──────────────────────┬────────────────┬──────────┬────────────────────────────┐
│ Languages            │ Minimal        │ Chomsky  │ Unrestricted               │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│ Recursive            │ Turing machine │ Finite   │     space indented         │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│ Regular              │ Grammars       │          │ ➀ unicode may render oddly │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│ 1 2  3   4    spaces │                │ Symbol-& │ but the column count is ok │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│                      │                │          │ Context                    │
└──────────────────────┴────────────────┴──────────┴────────────────────────────┘

#!/bin/bash
{ echo -e "<html>\n<table border=1 cellpadding=0 cellspacing=0>"
  paste "$@" |sed -re 's#(.*)#\x09\1\x09#' -e 's#\x09# </pre></td>\n<td><pre> #g' -e 's#^ </pre></td>#<tr>#' -e 's#\n<td><pre> $#\n</tr>#'
  echo -e "</table>\n</html>"
} |w3m -dump -T 'text/html'

---

Резюме инструментов представлено в ответах (до сих пор).
У меня было достаточно близкое, смотрят на них; вот то, что я нашел:

paste # Этот инструмент характерен для всех ответов, представленных до сих пор #, Он может обработать несколько файлов; поэтому несколько столбцов... Хороший! # Это разграничивает каждый столбец с Вкладкой... Хороший. # Его вывод не сведен в таблицу.

Все инструменты ниже всех удаляют этот разделитель!... Плохо, если Вам нужен разделитель.

column # Это удаляет Разграничитель табуляции, таким образом, полевая идентификация просто столбцами, которые это, кажется, обрабатывает вполне хорошо.. Я ничего не определил криво... # Кроме не наличия уникального разделителя, это хорошо работает!

expand # Только имеет единственную установку позиции табуляции, таким образом, это непредсказуемо вне 2 столбцов #, выравнивание столбцов не точно при обработке unicode, и это удаляет Разграничитель табуляции, таким образом, полевая идентификация просто выравниванием столбца

pr # Только имеет единственную установку позиции табуляции, таким образом, это непредсказуемо вне 2 столбцов. #, который выравнивание столбцов не точно при обработке unicode, и оно удаляет Разграничитель табуляции, таким образом, полевая идентификация просто выравниванием столбца

Мне, column это очевидное лучшее решение как острота.. Он Вы хотите или разделитель или табулирование ASCII-творчества Ваших файлов, продолжал читать, иначе.. columns чертовски хорошо :)...


Вот сценарий, который берет любой numper файлов и создает сведенную в таблицу презентацию ASCII-творчества.. (Примите во внимание, что unicode не может представить к ожидаемой ширине, например, ௵, который является отдельным символом. Это очень отличается к номерам столбцов, являющимся неправильным, как имеет место в некоторых упомянутых выше утилитах.)... Вывод сценария, показанный ниже, из 4 входных файлов, названных F1 F2 F3 F4...

+------------------------+-------------------+-------------------+--------------+
| Languages              | Minimal automaton | Chomsky hierarchy | Grammars     |
| Recursively enumerable | Turing machine    | Type-0            | Unrestricted |
| Regular                | Finite            | —                 |              |
| Alphabet               |                   | Symbol            |              |
|                        |                   |                   | Context      |
+------------------------+-------------------+-------------------+--------------+

#!/bin/bash

# Note: The next line is for testing purposes only!
set F1 F2 F3 F4 # Simulate commandline filename args $1 $2 etc...

p=' '                                # The pad character
# Get line and column stats
cc=${#@}; lmax=                      # Count of columns (== input files)
for c in $(seq 1 $cc) ;do            # Filenames from the commandline 
  F[$c]="${!c}"        
  wc=($(wc -l -L <${F[$c]}))         # File length and width of longest line 
  l[$c]=${wc[0]}                     # File length  (per file)
  L[$c]=${wc[1]}                     # Longest line (per file) 
  ((lmax<${l[$c]})) && lmax=${l[$c]} # Length of longest file
done
# Determine line-count deficits  of shorter files
for c in $(seq 1 $cc) ;do  
  ((${l[$c]}<lmax)) && D[$c]=$((lmax-${l[$c]})) || D[$c]=0 
done
# Build '\n' strings to cater for short-file deficits
for c in $(seq 1 $cc) ;do
  for n in $(seq 1 ${D[$c]}) ;do
    N[$c]=${N[$c]}$'\n'
  done
done
# Build the command to suit the number of input files
source=$(mktemp)
>"$source" echo 'paste \'
for c in $(seq 1 $cc) ;do
    ((${L[$c]}==0)) && e="x" || e=":a -e \"s/^.{0,$((${L[$c]}-1))}$/&$p/;ta\""
    >>"$source" echo '<(sed -re '"$e"' <(cat "${F['$c']}"; echo -n "${N['$c']}")) \'
done
# include the ASCII-art Table framework
>>"$source" echo ' | sed  -e "s/.*/| & |/" -e "s/\t/ | /g" \'   # Add vertical frame lines
>>"$source" echo ' | sed -re "1 {h;s/[^|]/-/g;s/\|/+/g;p;g}" \' # Add top and botom frame lines 
>>"$source" echo '        -e "$ {p;s/[^|]/-/g;s/\|/+/g}"'
>>"$source" echo  
# Run the code
source "$source"
rm     "$source"
exit

Вот мой исходный ответ (обрезал немного вместо вышеупомянутого сценария),

Используя wc получить ширину столбца, и sed к правильной клавиатуре с видимым символом . (только для этого примера)... и затем paste присоединиться к двум столбцам с символом Вкладки...

paste <(sed -re :a -e 's/^.{1,'"$(($(wc -L <F1)-1))"'}$/&./;ta' F1) F2

# output (No trailing whitespace)
Languages.............  Minimal automaton
Recursively enumerable  Turing machine
Regular...............  Finite

Если Вы хотите увеличить правый столбец:

paste <( sed -re :a -e 's/^.{1,'"$(($(wc -L <F1)-1))"'}$/&./;ta' F1 ) \
      <( sed -re :a -e 's/^.{1,'"$(($(wc -L <F2)-1))"'}$/&./;ta' F2 )  

# output (With trailing whitespace)
Languages.............  Minimal automaton
Recursively enumerable  Turing machine...
Regular...............  Finite...........
9
27.01.2020, 19:33
  • 1
    Спасибо! Вы сделали довольно большую работу. Это удивительно. –  StackExchange for All 14.07.2011, 06:00

Вы почти там. paste помещает символ табуляции между каждым столбцом, таким образом, все, что необходимо сделать, разворачивают вкладки. (Я предполагаю, что Ваши файлы не содержат вкладки.) Действительно необходимо определить ширину левого столбца. С (достаточно недавний) утилиты GNU, wc -L показывает длину самой длинной строки. В других системах сделайте первичную обработку с awk. +1 сумма пробела, который Вы хотите между столбцами.

paste left.txt right.txt | expand -t $(($(wc -L <left.txt) + 1))
paste left.txt right.txt | expand -t $(awk 'n<length {n=length} END {print n+1}')

Если у Вас есть утилита столбца BSD, можно использовать ее, чтобы определить ширину столбца и развернуть вкладки сразу. ( литеральный символ табуляции; под bash/ksh/zsh можно использовать $'\t' вместо этого, и в любой оболочке можно использовать "$(printf '\t')".)

paste left.txt right.txt | column -s '␉' -t
5
27.01.2020, 19:33
  • 1
    В моей версии wc, команда должна быть: wc -L <left.txt ... потому что, когда имя файла является spedified как аргументом командной строки, его имя производится к stdout –  Peter.O 11.07.2011, 19:18

Это является многоступенчатым, таким образом, это неоптимально, но здесь идет.

1) Найдите длину самой длинной строки в file1.txt.

while read line
do
echo ${#line}
done < file1.txt | sort -n | tail -1

С Вашим примером самая длинная строка равняется 22.

2) Используйте awk для заполнения file1.txt, дополнение каждой строки меньше чем 22 символа до 22 с printf оператор.

awk 'FS="---" {printf "%-22s\n", $1}' < file1.txt > file1-pad.txt

Примечание: Для FS используйте строку, которая не существует в file1.txt.

3) Используйте вставку, как Вы сделали прежде.

$ paste file1-pad.txt file2.txt
Languages               Minimal automaton
Recursively enumerable  Turing machine
Regular                 Finite

Если это - что-то, что Вы часто делаете, это может легко быть превращено в сценарий.

4
27.01.2020, 19:33
  • 1
    В Вашем коде для нахождения самой длинной строки Вам нужно while IFS= read -r line, иначе оболочка исказит пробел и обратные косые черты. Но оболочка не является лучшим инструментом для того задания; последние версии GNU coreutils имеют wc -L (см. ответ fred), или можно использовать awk: awk 'n<length {n=length} END {print +n}'. –  Gilles 'SO- stop being evil' 11.07.2011, 16:20

Я не могу прокомментировать ответ Гленна Джекмана, поэтому добавляю его для решения проблемы пустых ячеек, которую заметил Питер О. Добавление нулевого символа перед каждой вкладкой устраняет запуски разделителей, которые рассматриваются как единичный перерыв, и решает проблему. (Изначально я использовал пробелы, но использование нулевого символа char устраняет лишнее пространство между колонками.)

paste file1 file2 | sed 's/\t/\0\t/g' | column -s $'\t' -t

Если нулевой символ char вызывает проблемы по разным причинам, попробуйте:

paste file1 file2 | sed 's/\t/ \t/g' | column -s $'\t' -t

или

paste file1 file2 | sed $'s/\t/ \t/g' | column -s $'\t' -t

Как sed, так и column по-видимому, различаются в реализации для разных вкусов и версий Unix/Linux, особенно BSD (и Mac OS X) против GNU/Linux.

4
27.01.2020, 19:33

Основываясь на ответе Бахамата : это можно сделать полностью в awk , {{1} } чтение файлов только один раз и не создание временных файлов. Чтобы решить указанную проблему, выполните

awk '
        NR==FNR { if (length > max_length) max_length = length
                  max_FNR = FNR
                  save[FNR] = $0
                  next
                }
                { printf "%-*s", max_length+2, save[FNR]
                  print
                }
        END     { if (FNR < max_FNR) {
                        for (i=FNR+1; i <= max_FNR; i++) print save[i]
                  }
                }
    '   file1 file2

. Как и многие сценарии awk подобного рода, приведенный выше сначала читает file1 , сохраняя все данные в сохраняют массив и одновременно вычисляют максимальную длину строки. Затем он читает file2 и печатает сохраненные ( file1 ) данные рядом с текущими ( file2 ) данные. Наконец, если file1 длиннее, чем file2 (имеет больше строк), мы печатаем последние несколько строк file1 (те, для которых нет соответствующей строки во втором столбце).

Что касается формата printf :

  • «% - nn печатает строку с выравниванием по левому краю в поле nn символов в ширину.
  • "% - * s", nn делает то же самое - * указывает ему брать ширину поля из следующего параметра.
  • Используя maxlength +2 для nn , мы получаем два пробела между столбцами. Очевидно, +2 можно отрегулировать.

Приведенный выше сценарий работает только для двух файлов. Его можно тривиально изменить для обработки трех файлов, или для обработки четырех файлов и т. Д. , но это будет утомительно и оставлено как упражнение. Однако оказалось несложно изменить его для обработки любого количества файлов:

awk '
        FNR==1  { file_num++ }
                { if (length > max_length[file_num]) max_length[file_num] = length
                  max_FNR[file_num] = FNR
                  save[file_num,FNR] = $0
                }
        END     { for (j=1; j<=file_num; j++) {
                        if (max_FNR[j] > global_max_FNR) global_max_FNR = max_FNR[j]
                  }
                  for (i=1; i<=global_max_FNR; i++) {
                        for (j=1; j<file_num; j++) printf "%-*s", max_length[j]+2, save[j,i]
                        print save[file_num,i]
                  }
                }
    '   file*

Это очень похоже на мой первый сценарий, за исключением

  • ] Превращает max_length в массив.
  • Превращает max_FNR в массив.
  • Превращает save в двумерный массив.
  • Он читает все файлы, сохраняя все содержимое. Затем он записывает весь вывод из блока END .
0
27.01.2020, 19:33

Теги

Похожие вопросы