Bash에서 테이블 열을 어떻게 정렬 할 수 있습니까?


86

표 형식 텍스트를 출력하고 싶습니다. 내가하려고 한 것은 '\ t'로 배열 요소를 에코하는 것이었지만 잘못 정렬되었습니다.

내 코드

for((i=0;i<array_size;i++));
do
   echo stringarray[$i] $'\t' numberarray[$i] $'\t' anotherfieldarray[$i]
done;

내 출력

a very long string..........     112232432      anotherfield
a smaller string         123124343     anotherfield

원하는 출력

a very long string..........     112232432      anotherfield
a smaller string                 123124343      anotherfield

답변:


95

printf 훌륭하지만 사람들은 그것을 잊어 버립니다.

$ for num in 1 10 100 1000 10000 100000 1000000; do printf "%10s %s\n" $num "foobar"; done
         1 foobar
        10 foobar
       100 foobar
      1000 foobar
     10000 foobar
    100000 foobar
   1000000 foobar

$ for((i=0;i<array_size;i++));
do
    printf "%10s %10d %10s" stringarray[$i] numberarray[$i] anotherfieldarray[%i]
done

%10s문자열에 사용 했습니다. %s중요한 부분입니다. 문자열을 사용하도록 지시합니다. 10중간은 될 것입니다 얼마나 많은 열을 말한다. %d숫자 (숫자)입니다.

man 1 printf 더 많은 정보를 위해서.


35
표를 인쇄 할 때 유용한 한 가지 조언 : %-10swiil은 길이가 10 인 왼쪽 정렬 문자열을 생성합니다 .
steffen

@UtahJarhead 변수 stringarray [$ i]에 대한 참조는 $ {stringarray [i]}로 대체되어야하며 첫 번째 문자열 공백이 있어야 공백 문자가 a로 해석되지 않도록 "$ {stringarray [i]}"로 따옴표로 묶어야합니다. 구분자.
Daniel Perez

150

열 명령 사용 :

column -t -s' ' filename

데이터의 첫 번째 열에 공백이 있으므로 질문에 제공된 예제에서는 작동하지 않습니다.
Burhan Ali

1
@BurhanAli 이전 댓글을 반복해야합니까? 모든 답변은 일부 구분자를 가정합니다. OP는 구분 기호에 대해 말하지 않았습니다. 따라서 동일한 구분 기호를 열에서도 사용할 수 있습니다. 데이터의 첫 번째 열에 공백이 있기 때문에 어떻게 첫 번째 열 이라고 부르 나요?
PP

1
반복 할 필요가 없습니다. 나는 그들을 읽었다. 내 의견은 질문에서 원하는 출력을 기반으로합니다. 주어진 입력에이 대답을 사용하면 원하는 출력이 생성되지 않습니다.
부르 한 알리

@BurhanAli printf를 사용하더라도 구분 기호를 알아야합니다. %s형식 지정자는 공백을 구분자로 사용합니다. 이 경우 여기에있는 답변 중 어느 것도 작동하지 않습니다. 어떤 도구를 사용 하든 구문 분석 이 입력의 구분 기호에 의존 할 때 원하는 출력 에 대해 반복적으로 이야기하는 것이 놀랍습니다.
PP

2
구분 기호를 준비하기위한 예 :cat /etc/fstab | sed -r 's/\s+/ /g' | column -t -s' '
untore

16

필요한 것과 똑같은 출력을 얻으려면 다음과 같이 파일 형식을 지정해야합니다.

a very long string..........\t     112232432\t     anotherfield\n
a smaller string\t      123124343\t     anotherfield\n

그리고 다음을 사용합니다.

$ column -t -s $'\t' FILE
a very long string..........  112232432  anotherfield
a smaller string              123124343  anotherfield

2
무엇 $$'\t'거야?
rjmunro

2 개의 열이 약 5 자 이상 크기가 다른 경우 탭 중지를 사용할 수 없게됩니다.
UtahJarhead 2015 년


16
function printTable()
{
    local -r delimiter="${1}"
    local -r data="$(removeEmptyLines "${2}")"

    if [[ "${delimiter}" != '' && "$(isEmptyString "${data}")" = 'false' ]]
    then
        local -r numberOfLines="$(wc -l <<< "${data}")"

        if [[ "${numberOfLines}" -gt '0' ]]
        then
            local table=''
            local i=1

            for ((i = 1; i <= "${numberOfLines}"; i = i + 1))
            do
                local line=''
                line="$(sed "${i}q;d" <<< "${data}")"

                local numberOfColumns='0'
                numberOfColumns="$(awk -F "${delimiter}" '{print NF}' <<< "${line}")"

                # Add Line Delimiter

                if [[ "${i}" -eq '1' ]]
                then
                    table="${table}$(printf '%s#+' "$(repeatString '#+' "${numberOfColumns}")")"
                fi

                # Add Header Or Body

                table="${table}\n"

                local j=1

                for ((j = 1; j <= "${numberOfColumns}"; j = j + 1))
                do
                    table="${table}$(printf '#| %s' "$(cut -d "${delimiter}" -f "${j}" <<< "${line}")")"
                done

                table="${table}#|\n"

                # Add Line Delimiter

                if [[ "${i}" -eq '1' ]] || [[ "${numberOfLines}" -gt '1' && "${i}" -eq "${numberOfLines}" ]]
                then
                    table="${table}$(printf '%s#+' "$(repeatString '#+' "${numberOfColumns}")")"
                fi
            done

            if [[ "$(isEmptyString "${table}")" = 'false' ]]
            then
                echo -e "${table}" | column -s '#' -t | awk '/^\+/{gsub(" ", "-", $0)}1'
            fi
        fi
    fi
}

function removeEmptyLines()
{
    local -r content="${1}"

    echo -e "${content}" | sed '/^\s*$/d'
}

function repeatString()
{
    local -r string="${1}"
    local -r numberToRepeat="${2}"

    if [[ "${string}" != '' && "${numberToRepeat}" =~ ^[1-9][0-9]*$ ]]
    then
        local -r result="$(printf "%${numberToRepeat}s")"
        echo -e "${result// /${string}}"
    fi
}

function isEmptyString()
{
    local -r string="${1}"

    if [[ "$(trimString "${string}")" = '' ]]
    then
        echo 'true' && return 0
    fi

    echo 'false' && return 1
}

function trimString()
{
    local -r string="${1}"

    sed 's,^[[:blank:]]*,,' <<< "${string}" | sed 's,[[:blank:]]*$,,'
}

샘플 실행

$ cat data-1.txt
HEADER 1,HEADER 2,HEADER 3

$ printTable ',' "$(cat data-1.txt)"
+-----------+-----------+-----------+
| HEADER 1  | HEADER 2  | HEADER 3  |
+-----------+-----------+-----------+

$ cat data-2.txt
HEADER 1,HEADER 2,HEADER 3
data 1,data 2,data 3

$ printTable ',' "$(cat data-2.txt)"
+-----------+-----------+-----------+
| HEADER 1  | HEADER 2  | HEADER 3  |
+-----------+-----------+-----------+
| data 1    | data 2    | data 3    |
+-----------+-----------+-----------+

$ cat data-3.txt
HEADER 1,HEADER 2,HEADER 3
data 1,data 2,data 3
data 4,data 5,data 6

$ printTable ',' "$(cat data-3.txt)"
+-----------+-----------+-----------+
| HEADER 1  | HEADER 2  | HEADER 3  |
+-----------+-----------+-----------+
| data 1    | data 2    | data 3    |
| data 4    | data 5    | data 6    |
+-----------+-----------+-----------+

$ cat data-4.txt
HEADER
data

$ printTable ',' "$(cat data-4.txt)"
+---------+
| HEADER  |
+---------+
| data    |
+---------+

$ cat data-5.txt
HEADER

data 1

data 2

$ printTable ',' "$(cat data-5.txt)"
+---------+
| HEADER  |
+---------+
| data 1  |
| data 2  |
+---------+

REF LIB : https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash


감사! 이것이 바로 제가 찾던 것입니다. Mac 사용자의 경우 : -e대시를 올바르게 인쇄하려면 echo 명령에서 매개 변수 를 제거해야 합니다.
odm 2019

굉장하고 훌륭한 샘플! 감사!
오준영 19

출력 색상을 변경하면 정렬이 정말 엉망입니다. 확실하지 왜 ... 흠
mattdevio

@mattdevio 색상에 대한 수정 사항을 찾았습니까?
Carlos Florêncio 19

2
주의! 참조 링크에는 더 업데이트 된 기능이 있습니다.
서명

4

당신이 궁금해하는 것보다 쉽습니다.

세미콜론으로 구분 된 파일과 헤더로 작업하는 경우 :

$ (head -n1 file.csv && sort file.csv | grep -v <header>) | column -s";" -t

배열로 작업하는 경우 (탭을 구분 기호로 사용) :

for((i=0;i<array_size;i++));
do

   echo stringarray[$i] $'\t' numberarray[$i] $'\t' anotherfieldarray[$i] >> tmp_file.csv

done;

cat file.csv | column -t

4

awk stdin을 다루는 솔루션

columnPOSIX가 아니기 때문에 다음과 같습니다.

mycolumn() (
  file="${1:--}"
  if [ "$file" = - ]; then
    file="$(mktemp)"
    cat > "${file}"
  fi
  awk '
  FNR == 1 { if (NR == FNR) next }
  NR == FNR {
    for (i = 1; i <= NF; i++) {
      l = length($i)
      if (w[i] < l)
        w[i] = l
    }
    next
  }
  {
    for (i = 1; i <= NF; i++)
      printf "%*s", w[i] + (i > 1 ? 1 : 0), $i
    print ""
  }
  ' "$file" "$file"
  if [ "$1" = - ]; then
    rm "$file"
  fi
)

테스트:

printf '12 1234 1
12345678 1 123
1234 123456 123456
' > file

테스트 명령 :

mycolumn file
mycolumn <file
mycolumn - <file

모두를위한 출력 :

      12   1234      1
12345678      1    123
    1234 123456 123456

또한보십시오:


1
if [ "$file" = - ]; then말은해야한다 if [ "$1" = - ]; then. 현재 코드로는 임시 파일을 정리하지 않습니다.
Camusensei

3

어디에서 이것을 실행하고 있는지 확실하지 않지만 게시 한 코드는 적어도 내가 익숙한 bash에서는 제공하지 않은 출력을 생성하지 않습니다.

대신 이것을 시도하십시오.

stringarray=('test' 'some thing' 'very long long long string' 'blah')
numberarray=(1 22 7777 8888888888)
anotherfieldarray=('other' 'mixed' 456 'data')
array_size=4

for((i=0;i<array_size;i++))
do
    echo ${stringarray[$i]} $'\x1d' ${numberarray[$i]} $'\x1d' ${anotherfieldarray[$i]}
done | column -t -s$'\x1d'

파일에서 이러한 배열을 가져 오는 경우 탭이 포함될 수 있으므로 탭에 그룹 구분 문자 (1d)를 사용하고 있습니다.


0

누군가가 PHP에서 그렇게하고 싶다면 Github에 요점을 게시했습니다.

https://gist.github.com/redestructa/2a7691e7f3ae69ec5161220c99e2d1b3

간단히 전화 :

$output = $tablePrinter->printLinesIntoArray($items, ['title', 'chilProp2']);

7.2 이전의 PHP 버전을 사용하는 경우 코드를 조정해야 할 수 있습니다.

그 후 환경에 따라 echo 또는 writeLine을 호출하십시오.


0

아래 코드는 테스트를 거쳤으며 원래 질문에서 요청한대로 정확히 수행합니다.

매개 변수 : % 30s 30 자 열과 텍스트 오른쪽 정렬. % 10d 정수 표기법, % 10s도 작동합니다. 코드 주석에 대한 설명이 추가되었습니다.

stringarray[0]="a very long string.........."
# 28Char (max length for this column)
numberarray[0]=1122324333
# 10digits (max length for this column)
anotherfield[0]="anotherfield"
# 12Char (max length for this column)
stringarray[1]="a smaller string....."
numberarray[1]=123124343
anotherfield[1]="anotherfield"

printf "%30s %10d %13s" "${stringarray[0]}" ${numberarray[0]} "${anotherfield[0]}"
printf "\n"
printf "%30s %10d %13s" "${stringarray[1]}" ${numberarray[1]} "${anotherfield[1]}"
# a var string with spaces has to be quoted
printf "\n Next line will fail \n"      
printf "%30s %10d %13s" ${stringarray[0]} ${numberarray[0]} "${anotherfield[0]}"



  a very long string.......... 1122324333  anotherfield
         a smaller string.....  123124343  anotherfield

왼쪽 정렬 용으로 상술 @steffen 가리키는 같이 "-"기호의 printf 즉 $ {은 StringArray [0]} "" "는 -30s %"
다니엘 페레즈
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.