텍스트 파일을 열 단위로 결합


52

두 개의 텍스트 파일이 있습니다. 첫 번째 내용은 다음과 같습니다.

Languages
Recursively enumerable
Regular

두 번째 내용은 다음과 같습니다.

Minimal automaton
Turing machine
Finite

열 단위로 하나의 파일로 결합하고 싶습니다. 그래서 시도 paste 1 2하고 그 결과는 다음과 같습니다.

Languages   Minimal automaton
Recursively enumerable  Turing machine
Regular Finite

그러나 열을 다음과 같이 잘 정렬하고 싶습니다.

Languages               Minimal automaton
Recursively enumerable  Turing machine
Regular                 Finite

수동으로 처리하지 않고 달성 할 수 있는지 궁금합니다.


추가 :

다음은 Bruce 방법이 거의 손톱을 깎는 또 다른 예입니다.

$ cat 1
Chomsky hierarchy
Type-0
—

$ cat 2
Grammars
Unrestricted

$ paste 1 2 | pr -t -e20
Chomsky hierarchy   Grammars
Type-0              Unrestricted
—                    (no common name)

3
잘못 정렬 된 마지막 예는 멍청합니다. Arch linux, pr (GNU coreutils) 8.12에서 복제 할 수 있습니다. 나는 또한 다음과 같은 노인 슬랙웨어 (11.0)에 복제 할 수 없습니다 : pr (GNU coreutils) 5.97. 문제는 '-'문자에 있으며 붙여 넣기가 아니라 pr에 있습니다.
Bruce Ediger

1
나는 모두와 함께 EM-DASH와 같은 일을 얻을 pr하고 expand... columns이 문제를 방지 할 수 있습니다.
Peter.O

왼쪽 파일이 오른쪽보다 짧은 경우 가장 오른쪽 열을 왼쪽으로 이동시키는 awk + paste를 제외한 대부분의 다른 답변에 대한 출력을 생성 했습니다. 왼쪽 열의 빈 줄 에이 문제가있는 '붙여 넣기 + 열' 에도 동일하게 적용됩니다 ... 모든 출력을 함께 보려면. 여기에 링크가 있습니다 : paste.ubuntu.com/643692 4 열을 사용했습니다.
Peter.O

난 그냥에 오해의 소지가 뭔가 발견 paste.ubuntu의 나는 원래 내 스크립트를 테스트하기위한 데이터까지를 설정 (하고는 다른 일에했다) ... 그래서 말을 필드 ... 링크를 ➀ unicode may render oddly but the column count is ok 확실히 않습니다 하지 에 적용 wc-paste-pr하고 wc-paste-pr그들은을 열 개수 차이를 표시하십시오. 다른 것들은 괜찮습니다.
Peter.O

1
@BruceEdiger은 : 대부분의 아마도 나쁜 나에 의해 어떤 취급에 비 ASCII 문자를 사용하는 경우 정렬 문제는 () 문자 - - 대신 마이너스 (의) 자신의 질문에, 영업 이익은 대시 (사용) 발생 pr멀티 바이트의 현재 로케일의 문자 (일반적으로 UTF8)
WhiteWinterWolf

답변:


68

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 / 리눅스 확장"입니다. Fedora 시스템에 빈 셀 문제가 표시되지 않습니다. BSD에서 파생 된 것으로 보이며 매뉴얼 페이지에 "버전 2.23이 -s 옵션을 욕심 없게 변경했습니다"라고 표시되어 있습니다.


4
glenn : 당신은 시간의 영웅입니다! 나는 주변에 이와 같은 것이 있다는 것을 알았지 만 그것을 기억할 수 없었다. 나는이 질문에 숨어 있었다. 당신을 기다리고 있습니다 :) ... column물론; 얼마나 명백한 지 (
후시

4
방금 column -s $'\t' -t 을 무시 하여 오른쪽의 해당 셀에있는 모든 후속 셀을 왼쪽으로 이동시키는 것으로 나타났습니다. 즉, 파일에 빈 줄이 있거나 줄이 짧아지면 ... :(
Peter.O

1
@masi, 수정 됨
glenn jackman

-n은 RHEL에서 작동하지 않습니다. 대안이 있습니까?
Koshur

마지막으로 주석을 달 수 있으므로 이전에 null을 사용하여 빈 셀 실행과 관련된 Peter.O의 문제를 해결하는 답변을 아래에 추가했습니다.
테크노

11

편리한 dandy pr명령을 찾고 있습니다 .

paste file1 file2 | pr -t -e24

"-e24"는 "확장 탭 간격을 24 칸으로 늘립니다"입니다. 운 좋게도 paste열 사이에 탭 문자를 넣으면 pr확장 할 수 있습니다. "재귀 열거 가능"의 문자를 세고 2를 추가하여 24를 선택했습니다.


감사! "확장 탭이 24 칸으로 멈춤"은 무엇을 의미합니까?
Tim

또한 약간의 정렬 불량을 제외하고 귀하의 방법이 거의 손톱을 못 박는 예를 사용하여 업데이트합니다.
Tim

전통적으로 "탭 스톱 (tabstops)"은 8 칸마다 발생합니다. "123TABabc"는 줄의 시작 부분에서 'a'문자 8 문자 너비로 인쇄됩니다. 24로 설정하면 'a'가 줄의 시작부터 24 자 너비로 배치됩니다.
Bruce Ediger

"-e24"는 "탭 간격을 24 칸으로 확장" 이라고 말 하므로 expand명령을 직접 사용하지 마십시오 paste file1 file2 | expand -t 24.
WhiteWinterWolf

1
@Masi-내 대답은 비슷하지만 아래의 @techno의 대답과 덜 복잡합니다. 호출 sed하지 않으므로 실행되지 않는 프로세스가 하나 있습니다. 그것은 pr유닉스 SysV 시대에 거슬러 올라가는 고대 명령 인 것을 사용한다고 생각합니다 expand. 간단히 말해서 구식 학교입니다.
브루스 Ediger

9

업데이트 : 여기에 테이블 형식 출력을위한 훨씬 간단한 스크립트 (질문 끝에있는 스크립트)가 있습니다. 파일 이름을 원하는대로 전달하십시오 paste... html프레임을 만드는 데 사용 되므로 조정할 수 있습니다. 여러 공백을 유지하고 유니 코드 문자가 발생하면 열 정렬이 유지됩니다. 그러나 편집기 또는 뷰어 렌더러가 유니 코드를 만드는 방식은 완전히 다른 문제입니다 ...

┌──────────────────────┬────────────────┬──────────┬────────────────────────────┐
│ 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 열 이상으로 예측할 수 없습니다 # 유니 코드를 처리 할 때 열 정렬이 정확하지 않으며 탭 구분 기호를 제거하므로 필드 식별은 열 정렬에 의해 순전히

pr# 단일 탭 설정 만 있으므로 2 열 이상으로 예측할 수 없습니다. # 유니 코드를 처리 할 때 열의 정렬이 정확하지 않으며 탭 구분 기호를 제거하므로 필드 식별은 순전히 열 정렬에 의한 것입니다

나에게, column그것은 하나의 라이너로 명백한 최고의 해결책입니다 .. 당신은 파일의 구분 기호 또는 ASCII 예술 탭화를 원합니다. 그렇지 않으면 읽으십시오 columns.


다음은 많은 수의 파일을 가져 와서 ASCII로 표현 된 표 형식의 프리젠 테이션을 만드는 스크립트입니다. (유니 코드는 예상되는 너비로 렌더링되지 않을 수 있습니다. 위에서 언급 한 일부 유틸리티에서와 같이 숫자가 잘못되었습니다.) ... 아래에 표시된 스크립트의 출력은 F1 F2 F3 F4라는 이름의 4 개의 입력 파일에서 나옵니다.

+------------------------+-------------------+-------------------+--------------+
| 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열 너비를 얻기 위해, 그리고 sedA를 우측 패드에 보이는 문자 .(그냥 예를 들어) ... 그리고 pasteA를 두 열 가입 문자를 ...

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...........

감사! 당신은 꽤 많은 일을했습니다. 그 놀라운.
Tim

5

거의 다 왔습니다. 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

내 버전 wc에서 명령 wc -L <left.txt은 다음과 같아야 합니다. ... 파일 이름이 명령 줄 arg 로 전파 될 때 파일 이름이 stdout
Peter로

4

이것은 다단계이므로 최적이 아니지만 여기에갑니다.

1)에서 가장 긴 줄의 길이를 찾으십시오 file1.txt.

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

귀하의 예에서 가장 긴 줄은 22입니다.

2) awk를 사용 file1.txt하여 printf명령문에 각 줄을 22 자 미만으로 최대 22 자까지 채 웁니다.

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

이것이 자주하는 일이라면 쉽게 스크립트로 바꿀 수 있습니다.


가장 긴 줄을 찾으려면 코드에서 필요합니다 while IFS= read -r line. 그렇지 않으면 셸이 공백과 백 슬래시를 맹 글링합니다. 그러나 쉘은 해당 작업에 가장 적합한 도구는 아닙니다. GNU coreutils의 최신 버전이 있거나 wc -L(fred의 답변 참조) awk :를 사용할 수 있습니다 awk 'n<length {n=length} END {print +n}'.
Gilles 'SO- 악 그만해라'

4

나는 glenn jackman의 답변에 대해 언급 할 수 없으므로 Peter.O가 지적한 빈 셀 문제를 해결하기 위해 이것을 추가하고 있습니다. 각 탭 앞에 null 문자를 추가하면 단일 구분 기호로 취급되고 문제를 해결하는 구분 기호가 제거됩니다. (원래 공백을 사용했지만 null 문자를 사용하면 열 사이의 추가 공간이 제거됩니다.)

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

널 문자로 인해 여러 가지 이유로 문제점이 발생하면 다음 중 하나를 시도하십시오.

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맛과 GNU / 리눅스 대 유닉스 / 리눅스, 특히 BSD (및 Mac OS X)의 버전에서 구현 다양하게 나타납니다.


그 sed 명령은 아무것도하지 않는 것 같습니다. 열 명령을 바꾸고 od -cnull 바이트가 표시되지 않습니다. 이것은 centos와 우분투에 있습니다.
glenn jackman 2016 년

1
이것은 RedHat EL4에서 나를 위해 일했습니다. sed와 column은 시간과 시스템에 따라 변하는 것 같습니다. Ubuntu 14.4에서 사용 \0nullsed에서 작동하지 않았지만 작동했습니다 \x0. 그러나 열에 line too long오류가 발생했습니다. 가장 간단한 것은 공간을 사용하고 여분의 캐릭터와 함께 사는 것 같습니다.
techno

0

bahamat의 답변바탕으로 :이 작업은 전적으로 수행 할 수 있으며 awk파일을 한 번만 읽고 임시 파일을 만들지 않습니다. 명시된 문제를 해결하려면

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이 ilk의 많은 스크립트 와 마찬가지로 위의 첫 번째 읽기 file1는 모든 데이터를 save배열 에 저장 하고 동시에 최대 라인 길이를 계산합니다. 그런 다음 file2 저장된 ( file1) 데이터를 현재 ( file2) 데이터 와 나란히 읽고 인쇄합니다 . 마지막으로 file1길이가 길면 file2(행이 더 많음) 마지막 두 줄 file1 (두 번째 열에 해당 줄이없는 줄)을 인쇄합니다 .

printf형식 과 관련하여 :

  • "%-nns"필드 nn문자 너비가 왼쪽으로 정렬 된 문자열을 인쇄합니다 .
  • "%-*s", nn같은 일을합니다 – *다음 매개 변수에서 필드 너비를 가져 오도록 지시합니다.
  • for 를 사용 하면 열 사이에 두 개의 공백이 생깁니다. 분명히 조정될 수 있습니다.maxlength+2nn+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배열로 바뀝니다 .
  • 그것은 save2 차원 배열로 변 합니다.
  • 모든 파일을 읽고 모든 내용을 저장 합니다 . 그런 다음 블록의 모든 출력을 기록합니다 END.

나는이 질문이 오래되었다는 것을 안다. 나는 방금 넘어졌다. 이것이 paste최선의 해결책 이라는 데 동의합니다 . 특히 glenn jackman 's paste file1 file2 | column -s $'\t' -t입니다. 그러나 awk접근 방식 을 개선하는 것이 재미있을 것이라고 생각했습니다 .
G-Man
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.