Padding characters in printf

前端 未结 13 777
半阙折子戏
半阙折子戏 2020-11-30 16:58

I am writing a bash shell script to display if a process is running or not.

So far, I got this:

printf \"%-50s %s\\n\" $PROC_NAME [UP]
相关标签:
13条回答
  • 2020-11-30 17:32

    Pure Bash. Use the length of the value of 'PROC_NAME' as offset for the fixed string 'line':

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

    This gives

    abc ------------------------------------- [UP]
    abcdef ---------------------------------- [UP]
    
    0 讨论(0)
  • 2020-11-30 17:32

    I think this is the simplest solution. Pure shell builtins, no inline math. It borrows from previous answers.

    Just substrings and the ${#...} meta-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"
    

    Produces

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

    Produces

    -----<] A very long header
    ---------------<] shrt hdr
    
    0 讨论(0)
  • 2020-11-30 17:32

    Bash + seq to allow parameter expansion

    Similar to @Dennis Williamson answer, but if seq is available, the length of the pad string need not be hardcoded. The following code allows for passing a variable to the script as a positional parameter:

    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
    

    The ASCII code "2D" is used instead of the character "-" to avoid the shell interpreting it as a command flag. Another option is "3D" to use "=".

    In absence of any padlength passed as an argument, the code above defaults to the 80 character standard terminal width.

    To take advantage of the the bash shell variable COLUMNS (i.e., the width of the current terminal), the environment variable would need to be available to the script. One way is to source all the environment variables by executing the script preceded by . ("dot" command), like this:

    . /path/to/script
    

    or (better) explicitly pass the COLUMNS variable when executing, like this:

    /path/to/script $COLUMNS
    
    0 讨论(0)
  • 2020-11-30 17:34

    using echo only

    The anwser of @Dennis Williamson is working just fine except I was trying to do this using echo. Echo allows to output charcacters with a certain color. Using printf would remove that coloring and print unreadable characters. Here's the echo-only alternative:

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

    output:

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

    of course you can use all the variations proposed by @Dennis Williamson whether you want the right part to be left- or right-aligned (replacing 25 - ${#string1} by 25 - ${#string1} - ${#string2} etc...

    0 讨论(0)
  • 2020-11-30 17:42
    echo -n "$PROC_NAME $(printf '\055%.0s' {1..40})" | head -c 40 ; echo -n " [UP]"
    

    Explanation:

    • printf '\055%.0s' {1..40} - Create 40 dashes
      (dash is interpreted as option so use escaped ascii code instead)
    • "$PROC_NAME ..." - Concatenate $PROC_NAME and dashes
    • | head -c 40 - Trim string to first 40 chars
    0 讨论(0)
  • 2020-11-30 17:45

    Pure Bash, no external utilities

    This demonstration does full justification, but you can just omit subtracting the length of the second string if you want ragged-right lines.

    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
    

    Unfortunately, in that technique, the length of the pad string has to be hardcoded to be longer than the longest one you think you'll need, but the padlength can be a variable as shown. However, you can replace the first line with these three to be able to use a variable for the length of the pad:

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

    So the pad (padlimit and padlength) could be based on terminal width ($COLUMNS) or computed from the length of the longest data string.

    Output:

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

    Without subtracting the length of the second string:

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

    The first line could instead be the equivalent (similar to sprintf):

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

    or similarly for the more dynamic technique:

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

    You can do the printing all on one line if you prefer:

    printf '%s%*.*s%s\n' "$string1" 0 $((padlength - ${#string1} - ${#string2} )) "$pad" "$string2"
    
    0 讨论(0)
提交回复
热议问题