`column -t`와 같은 명령으로 대신 구분 기호를 출력으로 유지


17

간단한 테이블을 편집하고 있습니다. 멋지게 형식화하고 싶습니다. 내가 사용하는 수있는 동안 tbl, latex또는 유사한,이 잔인한 것 같다 - 일반 텍스트 정말 충분하다. 간단하기 때문에 소스가 출력이 될 수도 있습니다. 소스도 좋아 보일 것입니다. 이것은 완벽한 작업 인 것처럼 보입니다 column -s '|' -t. 분리 자를 찾고 각 열의 최대 너비에 따라 정렬 할 공간을 자동으로 삽입합니다. 불행히도 구분 기호를 삭제하므로 추가 편집 후 다시 실행할 수 없습니다. 출력을 입력으로 사용하기 위해 dem 등적으로 수행 할 수있는 좋은 텍스트 처리 도구가 있습니까? 아니면 내가 직접 써야합니까?

편집 : 여기 내가 원하는 것의 예가 있습니다.

foo |   bar | baz
abc def | 12 | 23456

되어야한다

foo     | bar | baz
abc def | 12  | 3456

' '분리와 스페이서 모두가, column -t잘 작동합니다. 그러나 내 항목에는 공백이 있으므로 사용할 수 없습니다. 스페이서가 분리막과 구별되게하면 문제가 복잡해집니다. 나는 구분 기호 옆에 구분 문자로 취급하는 것이 유용하다고 생각하지만 그렇게 column -s '|' -t하지는 않습니다 (현재의 행동은 분명히 유용합니다).


emacs org-mode를 사용할 수 있습니다. 테이블 지원은 실제로 매우 놀라운 기능으로 스프레드 시트를 제공합니다.
vschum

내가 생각하는 것만 큼 합리적인 것은 아니지만 leancrew.com/all-this/2008/08/tables-for-markdown-and-textmate 에 markdown 테이블을위한 python 프로그램이 있습니다.
wnoise

이것은 적어도 2 주마다 겪는 문제입니다. printf내가 지금까지 찾은 매번 홀로 코스트 를 우회 할 수있는 유일한 해결책 @은 데이터에 고유 한 문자 (예 :)를 추가하고 ... | column -s@ -t나중에 사용하는 것 입니다.
sjas

답변:


17

문제가 무엇인지 올바르게 이해하고 있는지 확실하지 않습니다. 그러나 추가 시간 분리기를 추가하여 해결할 수 있습니까? 따라서 두 번째 분리기를 사용하여 분판을 표시하고 원래 분리기를 그대로 유지하십시오.

각 "|"에 "@"을 추가하는이 예를 참조하십시오. 열 명령의 입력은 "xxx @ | yyyy"입니다. 열은 "|"를 유지하면서 "@"를 처리합니다. 손대지 않은:

~$ echo "foo | this is some text | bar" | sed 's/|/@|/g'  | column -s '@' -t
foo   | this is some text   | bar

영리한. 필자가 원하는 것을 거의 수행하고 실제로 요청한 것을 수행합니다. 구분 기호는 그대로 둡니다. 또한 실제 구분 기호 옆의 공간을 여기에서와 같이 위로 올리지 않고 아래로 조정할 수 있기를 원합니다.
nono

@wnoise : sed 's/ *| */@| /g'대신 사용
Stéphane Gimenez

@ Stéphane Gimenez : 추가 된 공간을 수정 sed 's/ |/|/g'한 후 column추가합니다. 우리는 이제 나를 위해 잘 작동하는 솔루션을 가지고 있습니다. (이와 같은 추가 캐릭터에 의존하지 않으면 좋을 것입니다. 사용할 수없는 경우 어떻게해야합니까?)
wnoise

3
@wnoise : @ 대신 낮은 ASCII 값과 같이 일반적으로 텍스트에 나타나지 않는 것을 사용할 수 있습니다. $ '\ x01'... (그러나 $ '\ x00'은 아님) ...
Peter.O

6

질문을 할 때 사용할 수 없었지만 v. 2.23 column 부터는 util-linux다음을 통해 출력 구분 기호를 선택할 수 있습니다 .

   -o, --output-separator string
          Specify the columns delimiter for table output (default is two spaces).

따라서 간단히 실행하십시오.

 column -s '|' -o '|' -t infile

util-linuxUbuntu 18.04 (및 아마도 다른 Debain 파생 배포판) 에서는이 버전을 쓸 수 없습니다. bsdmainutils버전 만 사용 가능합니다. bsdmainutils버전은 출력 형식을 지원하지 않습니다.
htaccess

5

다음은 bash 스크립트입니다. 'column -t`를 사용하지 않으며, 구분 기호는 IFS (또는 적어도 awk의 내부 버전 IFS)이므로 IFS와 동일하게 처리됩니다. 기본 구분 기호는 $'\ t '입니다.

이 스크립트는 가장 오른쪽 필드를 완전히 채 웁니다.
'열'은 이것을하지 않습니다.
모든 열을 채우면이 스크립트를
쉽게 수정하여 테이블 프레임도 만들 수 있습니다 .

노트. 입력 파일은 두 번 처리해야합니다
( '열'도이 작업을 수행해야 함)
첫 번째 단계는 열 최대 너비를 얻는 것입니다.
두 번째 단계는 필드를 확장하는 것입니다 (열당)

몇 가지 옵션을 추가 하고 눈부신 버그 수정 (이름 바꾸기 변수 :(

  • -l 들여 쓰기 된 필드의 왼쪽 트림 공백
  • -r 가장 넓은 텍스트보다 넓은 공백을 오른쪽으로 자릅니다 (열의 경우)
  • -b -l과 -r 모두
  • -L 왼쪽 출력 구분 기호가 추가되었습니다
  • -R 오른쪽 출력 구분 기호가 추가되었습니다
  • -B -L 및 -R 모두
  • -S 출력 분리기 선택

#!/bin/bash
#
#   script [-F sep] [file]
#
#   If file is not specified, stdin is read 
#    
# ARGS ######################################################################
l=;r=;L=;R=;O=;F=' ' # defaults
for ((i=1;i<=${#@};i++)) ;do
  case "$1" in
    -- ) shift 1;((i--));break ;;
    -l ) l="-l";shift 1;((i-=1)) ;;        #  left strip whitespace
    -r ) r="-r";shift 1;((i-=1)) ;;        # right strip whitespace
    -b ) l="-l";r="-r";shift 1;((i-=1)) ;; # strip  both -l and -r whitespace
    -L ) L="-L";shift 1;((i-=1)) ;;        #  Left output delimiter is added
    -R ) R="-R";shift 1;((i-=1)) ;;        # Right output delimiter is added
    -B ) L="-L";R="-R";shift 1;((i-=1)) ;; # output Both -L and -R delimiters
    -F ) F="$2";shift 2;((i-=2)) ;; # source separator
    -O ) O="$2";shift 2;((i-=2)) ;; # output  separator. Default = 1st char of -F 
    -* ) echo "ERROR: invalid option: $1" 1>&2; exit 1 ;;
     * ) break ;;
  esac
done
#
if  [[ -z "$1" ]] ;then # no filename, so read stdin
  f="$(mktemp)"
  ifs="$IFS"; IFS=$'\n'; set -f # Disable pathname expansion (globbing)
  while read -r line; do
    printf "%s\n" "$line" >>"$f"
  done
  IFS="$ifs"; set +f # re-enable pathname expansion (globbing)
else
  f="$1"
fi
[[ -f "$f" ]] || { echo "ERROR: Input file NOT found:" ;echo "$f" ;exit 2 ; }
[[ -z "$F" ]] && F=' '        # input Field Separator string
[[ -z "$O" ]] && O="$F"       # output Field Separator
                 O="${O:0:1}" #   use  single char only

# MAIN ######################################################################
max="$( # get max length of each field/column, and output them
  awk -vl="$l" -vr="$r" -vL="$L" -vR="$R" -vF="$F" -vO="$O" '
    BEGIN { if (F!="") FS=F }
    { for (i=1;i<=NF;i++) { 
        if (l=="-l") { sub("^[ \t]*","",$i) }
        if (r=="-r") { sub("[ \t]*$","",$i) }
        len=length($i); if (len>max[i]) { max[i]=len } 
        if (i>imax) { imax=i } 
      } 
    }
    END { for(i=1;i<=imax;i++) { printf("%s ",max[i]) } }
  ' "$f" 
)"

awk -vl="$l" -vr="$r" -vL="$L" -vR="$R" -vF="$F" -vO="$O" -v_max="$max" '
  BEGIN { if (F!="") FS=F; cols=split(_max,max," ") }
  { # Bring each field up to max len and output with delimiter
    printf("%s",L=="-L"?O:"")
    for(i=1;i<=cols;i++) { if (l=="-l") { sub("^[ \t]*","",$i) } 
                           if (r=="-r") { sub("[ \t]*$","",$i) }
      printf("%s%"(max[i]-length($i))"s%s",$i,"",i==cols?"":O) 
    } 
    printf("%s\n",R=="-R"?O:"")
  }
' "$f"

# END #######################################################################    
if  [[ -z "$1" ]] ;then # no filename, so stdin was used
  rm "$f"   # delete temp file
fi
exit

잘 했어요 물론, 실제로 새로운 프로그램을 작성하지 않아도되는 것을 기대하고있었습니다.
wnoise


1

이것은 hmontoliu 의 대답 에 대한 2 패스 조정으로 , 입력 데이터에서 구분 기호를 추측하여 구분 기호를 하드 코딩 할 필요가 없습니다.

  1. 공백으로 둘러싸인 영숫자가 아닌 단일 문자에 대한 입력을 구문 분석하고 가장 일반적인 문자를 기준으로 정렬하고 가장 일반적인 문자가에 지정된 구분 기호라고 가정합니다 $d.
  2. hmonoliu 의 답변 에서와 같이 다소 진행 되지만 PeterO 의 의견에 따라 ASCII NULL 을 패딩으로 사용합니다 .@

이 코드는 파일 이름을 받거나 STDIN 에서 입력하는 함수입니다 .

algn() { 
    d="$(grep -ow '[^[:alnum:]]' "${1:-/dev/stdin}"  | \
         sort | uniq -c | sort -rn | sed -n '1s/.*\(.$\)/\1/p')" ;
    sed "s/ *$d */\x01$d /g" "${1:-/dev/stdin}"  | column -s $'\001' -t ;
}

출력 algn foo(또는 algn < foo) :

foo      | bar  | baz
abc def  | 12   | 23456

1 년 후 이것을 살펴보면 STDIN 호출이 STDIN을 두 번 사용하기 때문에 작동하지 않거나 작동하지 않는 것처럼 보입니다 . 큰 파일 (약 8 천만 줄)로 테스트하면 파일이 올바르게 작동하는 것으로 나타납니다. 흠 ...
agc

0

hmontoliu 아이디어를 사용 하여 간단한 명령을 구현했습니다.

#! /bin/bash
delim="${1:-,}"
interm="${2:-\~}"
sed "s/$delim/$interm$delim/g" | column -t -s "$interm" | sed "s/  $delim/$delim/g"

논평:

  • ${1:-,}- ,기본적으로 첫 번째 인수입니다
  • 첫 번째 sed는 중간 심볼을 삽입합니다 ( $interm두 번째 인수 또는 ~기본적으로)
  • 그런 다음 column중간 심볼을 정렬하는 공백으로 바꿉니다.
  • 두 번째 sedcolumn명령 후 중복 공간을 정리합니다.

사용 예 :

$ echo "
a: bb: cccc
aaaa: b : cc
" | align :

a   : bb: cccc
aaaa: b : cc

또한 dem 등원이라는 점에서도 좋습니다. 여러 번 적용하고 동일한 결과를 얻을 수 있습니다 (예 : vim에서 편집하고 다시 정렬 할 때).

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