web-dev-qa-db-fra.com

Rembourrage des caractères dans printf

J'écris un script bash shell pour afficher si un processus est en cours d'exécution ou non.

Jusqu'ici, j'ai eu ceci:

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

Le code me donne cette sortie:

JBoss                                              [DOWN]

GlassFish                                          [UP]

verylongprocessname                                [UP]

Je veux combler le fossé entre les deux champs avec un '-' ou un * pour le rendre plus lisible. Comment puis-je faire cela sans perturber l'alignement des champs?

La sortie que je veux est:

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

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

verylongprocessname -----------------------------  [UP]
95
cordish

Pure Bash, pas d'utilitaire externe

Cette démonstration permet une justification complète, mais vous pouvez simplement omettre de soustraire la longueur de la deuxième chaîne si vous voulez des lignes droites irrégulières.

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

Malheureusement, dans cette technique, la longueur de la chaîne de pad doit être codée en dur pour être plus longue que celle la plus longue dont vous pensez avoir besoin, mais la longueur de pad peut être une variable comme indiqué. Cependant, vous pouvez remplacer la première ligne par ces trois pour pouvoir utiliser une variable pour la longueur du pad:

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

Ainsi, le pad (padlimit et padlength) pourrait être basé sur la largeur du terminal ($COLUMNS) ou calculé à partir de la longueur de la plus longue chaîne de données.

Sortie:

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

Sans soustraire la longueur de la deuxième chaîne:

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

La première ligne pourrait être l'équivalent (semblable à sprintf):

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

ou similaire pour la technique plus dynamique:

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

Vous pouvez imprimer sur une seule ligne si vous préférez:

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

Pure Bash. Utilisez la longueur de la valeur de 'PROC_NAME' comme décalage pour la chaîne fixe 'ligne':

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}}"

Cela donne

abc ------------------------------------- [UP]
abcdef ---------------------------------- [UP]
61
Fritz G. Mehner

Je pense que c'est la solution la plus simple. Commandes Pure Shell, pas de maths en ligne. Il emprunte aux réponses précédentes.

Juste des sous-chaînes et la méta-variable $ {# ...}.

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"

Produit

[>----- 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"

Produit

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

Solution triviale (mais efficace):

echo -e "---------------------------- [UP]\r$PROC_NAME "
14
Nicola Leoni

Il n’est pas possible de patiner avec autre chose que des espaces en utilisant printf. Vous pouvez utiliser sed:

printf "%-50s@%s\n" $PROC_NAME [UP] | sed -e 's/ /-/g' -e 's/@/ /' -e 's/-/ /'
11
F'x
echo -n "$PROC_NAME $(printf '\055%.0s' {1..40})" | head -c 40 ; echo -n " [UP]"

Explication:

  • printf '\055%.0s' {1..40} - Créer 40 tirets
    (le tiret est interprété comme une option, utilisez donc du code ascii d'échappement à la place)
  • "$PROC_NAME ..." - Concaténer $ PROC_NAME et des tirets
  • | head -c 40 - Couper la chaîne aux 40 premiers caractères
9
draganHR

Celui-ci est encore plus simple et n'exécute aucune commande externe.

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

JBoss............... [UP]
7
Chad Juliano

en utilisant echo uniquement

La réponse de Dennis Williamson @ fonctionne très bien, sauf que j'essayais de le faire en utilisant écho. Echo permet de générer des caractères d'une certaine couleur. Utiliser printf enlèverait cette coloration et imprimerait des caractères illisibles. Voici l'alternative echo uniquement:

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

sortie:

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

bien sûr, vous pouvez utiliser toutes les variations proposées par @Dennis Williamson, que vous souhaitiez que la partie droite soit alignée à gauche ou à droite (en remplaçant 25 - ${#string1} par 25 - ${#string1} - ${#string2} etc...

4
Chris Maes

Extension/remplissage/Pad/Padding de la console simple avec méthode et exemple de redimensionnement/redimensionnement automatique.

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";
}

Exemple:create-console-spanner "loading graphics module" "[success]"

Maintenant voici un complet-vedette-couleur-caractère-terminal-suite qui fait tout en ce qui concerne l'impression d'une couleur et style chaîne formatée avec une clé.

# 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 "\$@" | $(for k in ${!Paint[@]}; do echo -n Paint-replace \"\&$k\;\" \"\${Paint[$k]}\" \|; done) cat;
}
EOF
)

source <(cat <<EOF
function Paint-deactivate(){
    echo "\$@" | $(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}" "$@";
    (( 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";
}

Pour imprimer une couleur, c'est assez simple: Paint-format "&red;This is %s\n" red Et vous voudrez peut-être devenir gras plus tard: Paint-format "&bold;%s!\n" WOW

L'option -l De la fonction Paint-format Mesure le texte pour vous permettre d'effectuer des opérations de métrique de police de la console.

L'option -v De la fonction Paint-format Fonctionne de la même manière que printf mais ne peut pas être fournie avec -l

Maintenant pour l'étendre!

Paint-span "hello " . " &blue;world" [Note: nous n'avons pas ajouté de séquence terminale newline, mais le texte remplit le terminal, la ligne suivante apparaît donc uniquement comme une séquence terminale newline]

et le résultat est:

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

2
Hypersoft Systems

En voici un autre:

$ { 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]
2
thkala

Si vous terminez les caractères du pad avec un numéro de colonne fixe, vous pouvez alors recouvrir et cut à la longueur:

# 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"
2
Gurn

Simple mais ça marche:

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

Exemple d'utilisation:

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

Sortie sur la sortie standard:

JBoss -------------------------------------------- [DOWN]
GlassFish ---------------------------------------- [UP]
VeryLongProcessName ------------------------------ [UP]
1
Luis Daniel

Bash + seq pour permettre l'expansion des paramètres

Similaire à la réponse de @Dennis Williamson, mais si seq est disponible, la longueur de la chaîne de protection n'a pas besoin d'être codée en dur. Le code suivant permet de transmettre une variable au script en tant que paramètre de position:

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

Le code "2D" ASCII) est utilisé à la place du caractère "-" pour éviter que le shell ne l'interprète comme un indicateur de commande. Une autre option est "3D" pour utiliser "=".

En l'absence d'aucune longueur de pad passée en argument, le code ci-dessus utilise par défaut la largeur de terminal standard de 80 caractères.

Pour tirer parti de la variable shell bash COLUMNS (c'est-à-dire la largeur du terminal actuel), la variable d'environnement doit être disponible pour le script. L’une des méthodes consiste à rechercher toutes les variables d’environnement en exécutant le script précédé de . _ (commande "point"), comme ceci:

. /path/to/script

ou (mieux) explicitement passer la variable COLUMNS lors de l'exécution, comme ceci:

/path/to/script $COLUMNS
0
Loye Young