Заполнение символов в printf

Я пишу сценарий оболочки bash для отображения, если процесс запущен или нет.

До сих пор я получил это:

printf "%-50s %s\n" $PROC_NAME [UP]

Код дает мне этот результат:

JBoss                                              [DOWN]

GlassFish                                          [UP]

verylongprocessname                                [UP]

Я хочу заполнить пробел между двумя полями с помощью "-" или "*", чтобы сделать его более читаемым. Как это сделать, не нарушая выравнивание полей?

Результат, который я хочу:

JBoss -------------------------------------------  [DOWN]

GlassFish ---------------------------------------  [UP]

verylongprocessname -----------------------------  [UP]

Ответ 1

Pure Bash, без внешних утилит

Эта демонстрация полностью оправдывает себя, но вы можете просто опустить вычитание длины второй строки, если вы хотите неровные линии.

pad=$(printf '%0.1s' "-"{1..60})
padlength=40
string2='bbbbbbb'
for string1 in a aa aaaa aaaaaaaa
do
     printf '%s' "$string1"
     printf '%*.*s' 0 $((padlength - ${#string1} - ${#string2} )) "$pad"
     printf '%s\n' "$string2"
     string2=${string2:1}
done

К сожалению, в этом методе длина строки пэда должна быть жестко задана, чтобы быть длиннее, чем самая длинная, которая, как вы думаете, вам понадобится, но длина пэда может быть переменной, как показано. Однако вы можете заменить первую строку этими тремя, чтобы иметь возможность использовать переменную для длины пэда:

padlimit=60
pad=$(printf '%*s' "$padlimit")
pad=${pad// /-}

Таким образом, padlimit (padlimit и padlength) может основываться на ширине терминала ($COLUMNS) или вычисляться по длине самой длинной строки данных.

Выход:

a--------------------------------bbbbbbb
aa--------------------------------bbbbbb
aaaa-------------------------------bbbbb
aaaaaaaa----------------------------bbbb

Без вычитания длины второй строки:

a---------------------------------------bbbbbbb
aa--------------------------------------bbbbbb
aaaa------------------------------------bbbbb
aaaaaaaa--------------------------------bbbb

Вместо этого первая строка может быть эквивалентом (аналогично sprintf):

printf -v pad '%0.1s' "-"{1..60}

или аналогично для более динамичной техники:

printf -v pad '%*s' "$padlimit"

Вы можете сделать печать все в одну строку, если вы предпочитаете:

printf '%s%*.*s%s\n' "$string1" 0 $((padlength - ${#string1} - ${#string2} )) "$pad" "$string2"

Ответ 2

Чистый Bash. Используйте длину значения "PROC_NAME" как смещение для фиксированной строки "строка":

line='----------------------------------------'
PROC_NAME='abc'
printf "%s %s [UP]\n" $PROC_NAME "${line:${#PROC_NAME}}"
PROC_NAME='abcdef'
printf "%s %s [UP]\n" $PROC_NAME "${line:${#PROC_NAME}}"

Это дает

abc ------------------------------------- [UP]
abcdef ---------------------------------- [UP]

Ответ 3

Тривиальное (но работающее) решение:

echo -e "---------------------------- [UP]\r$PROC_NAME "

Ответ 4

Я думаю, что это самое простое решение. Чистые оболочки, нет встроенной математики. Он заимствует предыдущие ответы.

Просто подстроки и мета-переменная ${#...}.

A="[>---------------------<]";

# Strip excess padding from the right
#

B="A very long header"; echo "${A:0:-${#B}} $B"
B="shrt hdr"          ; echo "${A:0:-${#B}} $B"

Выдает

[>----- A very long header
[>--------------- shrt hdr


# Strip excess padding from the left
#

B="A very long header"; echo "${A:${#B}} $B"
B="shrt hdr"          ; echo "${A:${#B}} $B"

Выдает

-----<] A very long header
---------------<] shrt hdr

Ответ 5

Невозможно проложить что-либо, кроме пробелов, используя printf. Вы можете использовать sed:

printf "%[email protected]%s\n" $PROC_NAME [UP] | sed -e 's/ /-/g' -e 's/@/ /' -e 's/-/ /'

Ответ 6

echo -n "$PROC_NAME $(printf '\055%.0s' {1..40})" | head -c 40 ; echo -n " [UP]"

Пояснение:

  • printf '\055%.0s' {1..40} - Создайте 40 дефис
    (тире интерпретируется как опция, поэтому вместо этого используйте escape-код ascii)
  • "$PROC_NAME ..." - объединить $PROC_NAME и тире
  • | head -c 40 - Обрезать строку до первых 40 символов

Ответ 7

Это еще проще и не выполняет внешних команд.

$ PROC_NAME="JBoss"
$ PROC_STATUS="UP"
$ printf "%-.20s [%s]\n" "${PROC_NAME}................................" "$PROC_STATUS"

JBoss............... [UP]

Ответ 8

, используя echo только

Anwser of @Dennis Williamson работает отлично, но я пытаюсь сделать это с помощью эха. Echo позволяет выводить символы с определенным цветом. Использование printf удалит эту раскраску и напечатает нечитаемые символы. Здесь echo -одно альтернатива:

string1=abc
string2=123456
echo -en "$string1 "
for ((i=0; i< (25 - ${#string1}); i++)){ echo -n "-"; }
echo -e " $string2"

вывод:

abc ---------------------- 123456

конечно, вы можете использовать все варианты, предложенные @Dennis Williamson, хотите ли вы, чтобы правая часть была выровнена по левому или правому краю (заменив 25 - ${#string1} на 25 - ${#string1} - ${#string2} и т.д....

Ответ 9

Здесь еще один:

$ { echo JBoss DOWN; echo GlassFish UP; } | while read PROC STATUS; do echo -n "$PROC "; printf "%$((48-${#PROC}))s " | tr ' ' -; echo " [$STATUS]"; done
JBoss -------------------------------------------- [DOWN]
GlassFish ---------------------------------------- [UP]

Ответ 10

Если вы заканчиваете символы пэда с некоторым номером фиксированного столбца, вы можете сделать надстройку и cut длиной:

# Previously defined:
# PROC_NAME
# PROC_STATUS

PAD="--------------------------------------------------"
LINE=$(printf "%s %s" "$PROC_NAME" "$PAD" | cut -c 1-${#PAD})
printf "%s %s\n" "$LINE" "$PROC_STATUS"

Ответ 11

Простая консоль Span/Fill/Pad/Padding с автоматическим масштабированием/изменением размера Метод и пример.

function create-console-spanner() {
    # 1: left-side-text, 2: right-side-text
    local spanner="";
    eval printf -v spanner \'"%0.1s"\' "-"{1..$[$(tput cols)- 2 - ${#1} - ${#2}]}
    printf "%s %s %s" "$1" "$spanner" "$2";
}

Пример: create-console-spanner "loading graphics module" "[success]"

Теперь вот полнофункциональный набор цветных символов для терминала, который делает все, что касается печати строки, отформатированной в цвет и стиль, с помощью гаечного ключа.

# Author: Triston J. Taylor <[email protected]>
# Date: Friday, October 19th, 2018
# License: OPEN-SOURCE/ANY (NO-PRODUCT-LIABILITY OR WARRANTIES)
# Title: paint.sh
# Description: color character terminal driver/controller/suite

declare -A PAINT=([none]='tput sgr0' [bold]='tput bold' [black]='tput setaf 0' [red]='tput setaf 1' [green]='tput setaf 2' [yellow]='tput setaf 3' [blue]='tput setaf 4' [magenta]='tput setaf 5' [cyan]='tput setaf 6' [white]='tput setaf 7');

declare -i PAINT_ACTIVE=1;

function paint-replace() {
    local contents=$(cat)
    echo "${contents//$1/$2}"
}

source <(cat <<EOF
function paint-activate() {
    echo "\[email protected]" | $(for k in ${!PAINT[@]}; do echo -n paint-replace \"\&$k\;\" \"\${PAINT[$k]}\" \|; done) cat;
}
EOF
)

source <(cat <<EOF
function paint-deactivate(){
    echo "\[email protected]" | $(for k in ${!PAINT[@]}; do echo -n paint-replace \"\&$k\;\" \"\" \|; done) cat;    
}
EOF
)

function paint-get-spanner() {
    (( $# == 0 )) && set -- - 0;
    declare -i l=$(( 'tput cols' - ${2}))
    eval printf \'"%0.1s"\' "${1:0:1}"{1..$l}
}

function paint-span() {
    local left_format=$1 right_format=$3
    local left_length=$(paint-format -l "$left_format") right_length=$(paint-format -l "$right_format")
    paint-format "$left_format";
    paint-get-spanner "$2" $(( left_length + right_length));
    paint-format "$right_format";
}

function paint-format() {
    local VAR="" OPTIONS='';
    local -i MODE=0 PRINT_FILE=0 PRINT_VAR=1 PRINT_SIZE=2;
    while [[ "${1:0:2}" =~ ^-[vl]$ ]]; do
        if [[ "$1" == "-v" ]]; then OPTIONS=" -v $2"; MODE=$PRINT_VAR; shift 2; continue; fi;
        if [[ "$1" == "-l" ]]; then OPTIONS=" -v VAR"; MODE=$PRINT_SIZE; shift 1; continue; fi;
    done;
    OPTIONS+=" --"
    local format="$1"; shift;
    if (( MODE != PRINT_SIZE && PAINT_ACTIVE )); then
        format=$(paint-activate "$format&none;")
    else
        format=$(paint-deactivate "$format")
    fi
    printf $OPTIONS "${format}" "[email protected]";
    (( MODE == PRINT_SIZE )) && printf "%i\n" "${#VAR}" || true;
}

function paint-show-pallette() {
    local -i PAINT_ACTIVE=1
    paint-format "Normal: &red;red &green;green &blue;blue &magenta;magenta &yellow;yellow &cyan;cyan &white;white &black;black\n";
    paint-format "  Bold: &bold;&red;red &green;green &blue;blue &magenta;magenta &yellow;yellow &cyan;cyan &white;white &black;black\n";
}

Чтобы напечатать цвет, достаточно простой: paint-format "&red;This is %s\n" red И вы можете захотеть получить жирный шрифт позже: paint-format "&bold;%s!\n" WOW

Опция -l функции paint-format текст, чтобы вы могли выполнять операции с метрикой шрифта консоли.

Опция -v для функции paint-format работает так же, как printf но не может поставляться с -l

Теперь для охвата !

paint-span "hello ". " &blue;world" paint-span "hello ". " &blue;world" [примечание: мы не добавили последовательность терминала новой строки, но текст заполняет терминал, поэтому следующая строка выглядит только как последовательность терминала новой строки]

и результат этого:

hello............................. world

Ответ 12

Bash + seq для расширения параметров

Аналогично ответу @Dennis Williamson, но если доступен seq, длина строки пэда не должна быть жестко задана. Следующий код позволяет передавать переменную в скрипт в качестве позиционного параметра:

COLUMNS="${COLUMNS:=80}"
padlength="${1:-$COLUMNS}"
pad=$(printf '\x2D%.0s' $(seq "$padlength") )

string2='bbbbbbb'
for string1 in a aa aaaa aaaaaaaa
do
     printf '%s' "$string1"
     printf '%*.*s' 0 $(("$padlength" - "${#string1}" - "${#string2}" )) "$pad"
     printf '%s\n' "$string2"
     string2=${string2:1}
done

Код ASCII "2D" используется вместо символа "-", чтобы избежать интерпретации оболочкой его как флага команды. Другой вариант - "3D" для использования "=".

Если длина аргумента не указана в качестве аргумента, приведенный выше код по умолчанию равен стандартной ширине терминала в 80 символов.

Чтобы воспользоваться преимуществом переменной оболочки bash COLUMNS (т. COLUMNS Шириной текущего терминала), переменная окружения должна быть доступна для сценария. Одним из способов является получение всех переменных среды путем выполнения сценария, которому предшествует . (команда "точка"), вот так:

. /path/to/script

или (лучше) явно передать COLUMNS при выполнении, например так:

/path/to/script $COLUMNS

Ответ 13

Просто, но это работает:

printf "%-50s%s\n" "$PROC_NAME~" "~[UP]" | tr ' ~' '- '

Пример использования:

while read PROC_NAME STATUS; do  
    printf "%-50s%s\n" "$PROC_NAME~" "~[$STATUS]" | tr ' ~' '- '
done << EOT 
JBoss DOWN
GlassFish UP
VeryLongProcessName UP
EOT

Вывод на стандартный вывод:

JBoss -------------------------------------------- [DOWN]
GlassFish ---------------------------------------- [UP]
VeryLongProcessName ------------------------------ [UP]