Command like `column -t` that instead keeps separators in output
Not sure if I understand right what is your problem. But, can it be solved adding an additional temporal separator? hence you can use the second separator to mark the separations, keeping the original separator untouched.
See this example where I add a "@" to each of the "|" so the input of the column command would be "xxx @| yyyy". Column will process the "@" keeping the "|" untouched:
~$ echo "foo | this is some text | bar" | sed 's/|/@|/g' | column -s '@' -t
foo | this is some text | bar
This wasn't available when you asked the question but as of v. 2.23 column
from util-linux
allows you to select the output separator via
-o, --output-separator string
Specify the columns delimiter for table output (default is two spaces).
So simply run:
column -s '|' -o '|' -t infile
Here is a bash script. It does not use 'column -t`, and the seperator is handled exactly as is the IFS, because it is the IFS (or at least, awk's internal version of the IFS)... The default delimiter is $' \t'
This script fully pads out the rightmost field.
'column' does not do this.
By padding out all the columns, this script can be
easily modified to create a table frame as well.
Note. The input file needs to be processed twice
('column' would also need to do this)
The first pass is to get column max widths.
The second pass is to expand fields (per column)
Added some options and fixed a glaring bug (renaming variables :(
- -l Left trim whitespace of any indented fields
- -r Right trim whitespace wider than widest text (for the column)
- -b Both -l and -r
- -L Left output delimiter is added
- -R Right output delimiter is added
- -B Both -L and -R
- -S Choose output seperator
#!/bin/bash
#
# script [-F sep] [file]
#
# If file is not specified, stdin is read
#
# ARGS ######################################################################
l=;r=;L=;R=;O=;F=' ' # defaults
for ((i=1;i<=${#@};i++)) ;do
case "$1" in
-- ) shift 1;((i--));break ;;
-l ) l="-l";shift 1;((i-=1)) ;; # left strip whitespace
-r ) r="-r";shift 1;((i-=1)) ;; # right strip whitespace
-b ) l="-l";r="-r";shift 1;((i-=1)) ;; # strip both -l and -r whitespace
-L ) L="-L";shift 1;((i-=1)) ;; # Left output delimiter is added
-R ) R="-R";shift 1;((i-=1)) ;; # Right output delimiter is added
-B ) L="-L";R="-R";shift 1;((i-=1)) ;; # output Both -L and -R delimiters
-F ) F="$2";shift 2;((i-=2)) ;; # source separator
-O ) O="$2";shift 2;((i-=2)) ;; # output separator. Default = 1st char of -F
-* ) echo "ERROR: invalid option: $1" 1>&2; exit 1 ;;
* ) break ;;
esac
done
#
if [[ -z "$1" ]] ;then # no filename, so read stdin
f="$(mktemp)"
ifs="$IFS"; IFS=$'\n'; set -f # Disable pathname expansion (globbing)
while read -r line; do
printf "%s\n" "$line" >>"$f"
done
IFS="$ifs"; set +f # re-enable pathname expansion (globbing)
else
f="$1"
fi
[[ -f "$f" ]] || { echo "ERROR: Input file NOT found:" ;echo "$f" ;exit 2 ; }
[[ -z "$F" ]] && F=' ' # input Field Separator string
[[ -z "$O" ]] && O="$F" # output Field Separator
O="${O:0:1}" # use single char only
# MAIN ######################################################################
max="$( # get max length of each field/column, and output them
awk -vl="$l" -vr="$r" -vL="$L" -vR="$R" -vF="$F" -vO="$O" '
BEGIN { if (F!="") FS=F }
{ for (i=1;i<=NF;i++) {
if (l=="-l") { sub("^[ \t]*","",$i) }
if (r=="-r") { sub("[ \t]*$","",$i) }
len=length($i); if (len>max[i]) { max[i]=len }
if (i>imax) { imax=i }
}
}
END { for(i=1;i<=imax;i++) { printf("%s ",max[i]) } }
' "$f"
)"
awk -vl="$l" -vr="$r" -vL="$L" -vR="$R" -vF="$F" -vO="$O" -v_max="$max" '
BEGIN { if (F!="") FS=F; cols=split(_max,max," ") }
{ # Bring each field up to max len and output with delimiter
printf("%s",L=="-L"?O:"")
for(i=1;i<=cols;i++) { if (l=="-l") { sub("^[ \t]*","",$i) }
if (r=="-r") { sub("[ \t]*$","",$i) }
printf("%s%"(max[i]-length($i))"s%s",$i,"",i==cols?"":O)
}
printf("%s\n",R=="-R"?O:"")
}
' "$f"
# END #######################################################################
if [[ -z "$1" ]] ;then # no filename, so stdin was used
rm "$f" # delete temp file
fi
exit