Bash – Limit rows max and min length

bash

I have this input:

XX3083136|bla-bla texthere texttt|asfdasfd@safdsadf.com|SADFdsafsafd|ASDfasfdsafd|DSFSAFD|dsafasfd|sadfsad|
XX3083372|bla-bla-bla this is a text bla-bla|asdfsfda@lsadfasfdda.com|SDFsafas|SADFsa|DFSsdf|asdasdf|sadfdsafsaf|asdfsadf|

and I need this output:

XX3083136|bla-bla texthere textt|asfdasfd@safdsadf.com         |SADFdsafsafd|ASDfasfdsafd|DSFSAFD|dsafasfd|sadfsad|
XX3083372|bla-bla-bla this is a te|asdfsfda@lsadfasfdda.com      |SDFsafas|SADFsa|DFSsdf|asdasdf|sadfdsafsaf|asdfsadf|

So the difference is that I need to control the max text length between the "|". If it's shorter then given line lenght then " " need to be putted.
In this example the second row is limited to max 24 chars and the third row has to be at least 30 chars. Different rows will need different max/min limits..

How can I do this in bash?

Best Answer

To supplement a little:

Basic format for printf in text is:

%s      # Print as is
%10     # Right justify minimum width print 10
%-10    # Left justify minimum width print 10
%.10    # Max width 10
%10.10  # Max width 10, min width print 10
%-10.10 # Left justify, max width 10, min width print 10
%*s     # Same as above, but get number from arguments
%-*s    # Same as above, but get number from arguments
...

When one get long patterns it can become a bit messy to keep track on where and which etc. One way to make it a bit easier could be something like this:

#!/bin/bash

usage()
{
    printf "Usage: %s <FILE>\n" "$(basename "$0")" >&2
    [[ -n "$1" ]] && echo "$1"
    exit 1
}

if [[ ! -t 0 ]]; then
    : # Piped to
elif [[ $# -eq 0 ]]; then
    usage "Missing file."
elif [[ ! -r "$1" ]]; then
    usage "Unable to read \`$1'."
else
    # Accept input from file to file descriptor 0, aka stdin
    exec 0< "$1"
fi

fmt=""
fmt="$fmt%s|"       # F1
fmt="$fmt%-24.24s|" # F2
fmt="$fmt%-30s|"    # F3
fmt="$fmt%-10.10s|" # F4
fmt="$fmt%-10.10s|" # F5
fmt="$fmt%-10s|"    # F6
fmt="$fmt%-2.2s|"   # F7
fmt="$fmt%-2.2s|\n" # F8

# Set IFS to newline and bar and read fields
# assigning them to f1 ... f8
#
while IFS=$'\n'"|" read f1 f2 f3 f4 f5 f6 f7 f8; do
    printf "$fmt"\
    "$f1" "$f2" "$f3" "$f4" \
    "$f5" "$f6" "$f7" "$f8"
done <&0

Or. e.g.:

while IFS=$'\n'"|" read f1 f2 f3 f4 f5 f6 f7 f8; do
    printf "%s|%-*.*s|%-*s\n" \
    "$f1" \
    24 24 "$f2" \
    30 "$f3"
done < "input"

If it is only line parsing then awk is an good alternative. e.g.:

#!/usr/bin/awk -f

BEGIN {FS="|"}
/^/ {
    printf "%s|%-24.24s|%-30s|%-10.10s|%-10.10s|%-10s\n",
        $1, $2, $3, $4, $5, $6
}

Or:

#!/usr/bin/awk -f

BEGIN {
    FS="|"
}
/^/ {
    printf "%s|%-*.*s|%-*s|%-*.*s|%-*.*s|%-*s\n",
        $1,
        24, 24, $2,
        30, $3,
        10, 10, $4,
        10, 10, $5,
        10, $6
}
Related Question