Bash - 가변 길이 선 뒤에 수직선 그리기

Bash - 가변 길이 선 뒤에 수직선 그리기

다음 형식의 텍스트 파일이 있는데 줄 뒤에 수직선을 추가하고 숫자를 추가하고 싶습니다.

c4-1 d e c
c d e c
e-2 f g2
e4 f g2
g8-4\( a-5 g f\) e4 c
g'8\( a g f\) e4 c
c-1 r c2
c4 r c2 

다음과 같은 방법으로 행과 번호 매기기를 구현했습니다 while-loop.

#!/bin/bash

while read -r line; do
    if [ -z "$line" ]; then
        echo
        continue
    fi
    n=$((++n)) \
    && grep -vE "^$|^%" <<< "$line" \
    | sed 's/$/\ \|\ \%'$(("$n"))'/'
done < file

다음 출력을 얻습니다.

c4-1 d e c | %1
c d e c | %2
e-2 f g2 | %3
e4 f g2 | %4
g8-4\( a-5 g f\) e4 c | %5
g'8\( a g f\) e4 c | %6
c-1 r c2 | %7
c4 r c2 | %8

이제 콘텐츠 수직 정렬을 추가하고 다음과 같은 출력을 얻고 싶습니다.

c4-1 d e c            | %1
c d e c               | %2
e-2 f g2              | %3
e4 f g2               | %4
g8-4\( a-5 g f\) e4 c | %5
g'8\( a g f\) e4 c    | %6
c-1 r c2              | %7
c4 r c2               | %8

이는 가장 긴 줄의 줄 길이(여기서는 21자)와 공백이 추가된 각 줄의 줄 길이 사이의 차이를 어떻게든 얻어야 한다는 것을 의미합니다. 어떻게 해야 합니까?

답변1

정렬되지 않은 줄을 인쇄하고 column -t더미 구분 기호를 사용하여 출력 형식을 지정할 수 있습니다.

#!/bin/bash

while read -r line; do
  if [ -z "$line" ]; then
    echo
    continue
  fi
  printf '%s@| %%%s\n' "$line" "$((++n))"
done < file | column -e -s'@' -t | sed 's/ |/|/'

여기서는 @열의 끝을 표시하기 전에 더미 문자를 추가했습니다. 끝에 있는 |명령은 sed앞에 있는 추가 공백 문자를 제거합니다 |. -e출력에서 빈 줄을 유지하려면 옵션이 필요합니다 .

산출:

c4-1 d e c            | %1
c d e c               | %2
e-2 f g2              | %3
e4 f g2               | %4
g8-4\( a-5 g f\) e4 c | %5
g'8\( a g f\) e4 c    | %6
c-1 r c2              | %7
c4 r c2               | %8

답변2

awk+GNU를 사용하면 wc입력의 모든 문자가 단일 너비라고 가정합니다.

$ awk -v f="$(wc -L < ip.txt)" '{printf "%-*s | %%%s\n", f, $0, NR}' ip.txt
c4-1 d e c            | %1
c d e c               | %2
e-2 f g2              | %3
e4 f g2               | %4
g8-4\( a-5 g f\) e4 c | %5
g'8\( a g f\) e4 c    | %6
c-1 r c2              | %7
c4 r c2               | %8

답변3

일반 bash: bash 버전 >= 4.0

#!/bin/bash
mapfile -t lines < file
max=0
for line in "${lines[@]}"; do
    max=$(( ${#line} > max ? ${#line} : max ))
done
for i in "${!lines[@]}"; do
    printf "%-*s | %%%d\n" $max "${lines[i]}" $((i+1))
done

이전 bash 버전의 경우 맵 파일을 읽는 동안 루프로 바꾸십시오. 이는 버전 3.2에서 작동합니다.

#!/bin/bash
lines=()
max=0
while IFS= read -r line || [[ -n "line" ]]; do
    lines+=("$line")
    max=$(( ${#line} > max ? ${#line} : max ))
done < file
for i in "${!lines[@]}"; do
    printf "%-*s | %%%d\n" $max "${lines[i]}" $((i+1))
done

답변4

기록을 위해: (매우 느리지만 처음 시도하는 것입니다 wc -L.)
확실히 @Freddy의 답변을 사용할 것입니다 column!

#!/bin/bash

file="$1"

ll=$(wc -L < "$file")

while read -r line; do
    if [ -z "$line" ]; then
        echo
        continue
    fi
    sl=$(wc -L <<< "$line")
    if [ "$ll" = "$sl" ]; then
        as=$(echo "$ll - $sl" | bc)
    else
        as=$(echo "$ll - $sl + 1" | bc)
    fi
    space=$(printf '\ %.0s' $(seq "$as") )
    n=$((++n)) \
    && grep -vE "^$|^%" <<< "$line" \
    | sed "s/$/$space\ \|\ \%$(printf "%s" "$n")/"
done < "$file"

추가 공간을 사용하고 있지만:

c4-1 d e c             | %1
c d e c                | %2
e-2 f g2               | %3
e4 f g2                | %4
g8-4\( a-5 g f\) e4 c  | %5
g'8\( a g f\) e4 c     | %6
c-1 r c2               | %7
c4 r c2                | %8

관련 정보