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]
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"
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]
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
Solution triviale (mais efficace):
echo -e "---------------------------- [UP]\r$PROC_NAME "
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/-/ /'
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"$PROC_NAME ..."
- Concaténer $ PROC_NAME et des tirets| head -c 40
- Couper la chaîne aux 40 premiers caractèresCelui-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]
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...
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
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]
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"
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]
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