"column -t"와 같은 명령은 출력에서 ​​구분 기호를 유지합니다.

"column -t"와 같은 명령은 출력에서 ​​구분 기호를 유지합니다.

간단한 양식을 편집하고 있습니다. 포맷이 잘 되었으면 좋겠습니다. tbl이나 이와 유사한 것을 사용할 수도 있지만 latex이는 과도한 것처럼 보입니다. 일반 텍스트로도 충분합니다. 간단하기 때문에 소스를 출력으로 넣는 것이 좋을 것 같습니다. 따라서 소스도 보기 좋아야 합니다. 이것은 완벽한 작업을 수행해야 하는 것처럼 보입니다 column -s '|' -t. 구분 기호를 찾고 각 열의 최대 너비에 따라 정렬할 공백을 자동으로 삽입합니다. 불행히도 추가 편집 후에는 다시 실행할 수 없도록 구분 기호가 제거됩니다. 출력이 입력 역할을 하도록 멱등적으로 이를 수행할 수 있는 좋은 텍스트 처리 도구가 있습니까? 아니면 제가 직접 작성해야 하나요?

편집: 다음은 내가 원하는 것의 예입니다.

foo |   bar | baz
abc def | 12 | 23456

되어야 한다

foo     | bar | baz
abc def | 12  | 3456

분리기 와 스페이서는 ' '함께 사용하면 column -t매우 효과적입니다 . 하지만 내 아이템에 공백이 있어서 사용할 수 없습니다. 스페이서를 디바이더와 다르게 만드는 것은 상황을 복잡하게 만듭니다. 구분 기호 옆의 구분 기호로 처리하는 것이 유용할 것이라고 생각했지만 그렇지 않습니다 column -s '|' -t(분명히 현재 동작도 유용하지만).

답변1

귀하의 질문이 무엇인지 올바르게 이해했는지 잘 모르겠습니다. 하지만 추가 시간 구분 기호를 추가하면 이 문제가 해결됩니까? 따라서 두 번째 구분 기호를 사용하여 구분 기호를 표시하고 원래 구분 기호는 변경되지 않은 상태로 유지할 수 있습니다.

각 "|"에 "@"를 추가하여 열 명령에 대한 입력이 "xxx @| yyyy"가 되는 이 예를 참조하세요. 열은 "@"을 처리하고 "|"는 영향을 받지 않습니다.

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

답변2

문의하신 시점에는 이 기능을 사용할 수 없었으나,섹션 2.23 기준 columnfrom을 util-linux사용하면 출력 구분 기호를 선택할 수 있습니다.

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

그러니 그냥 실행하세요:

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

답변3

이것은 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

답변4

이는 2단계 조정입니다.헤르몬톨리우답변, 입력 데이터에서 구분 기호를 추측하여 하드 코딩할 필요가 없습니다.

  1. 공백으로 묶인 영숫자가 아닌 단일 문자에 대한 입력을 구문 분석하고 가장 일반적인 문자로 정렬하며 가장 일반적인 문자가 할당된 구분 기호라고 가정합니다 $d.
  2. 다소 진행헤르모놀리우답은 있지만 ASCII를 사용하는 것입니다.유효하지 않은@다음 대신 패딩으로피터 오의 의견.

코드는 파일 이름이나 입력을 받아들이는 함수입니다.표준 입력:

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

관련 정보