This is longer than battery's, but imho it splits the strings better. Also it uses printf for truncation where possible, falling back to other mechanisms only for left-hand truncation of the second argument.
Bash:
truncat () {
local len=$1 a=$2 b=$3 len_a=${#2} len_b=${#3}
if ((len <= 0)); then return
elif ((${len_b} == 0)); then
printf %-${len}.${len}s "$a"
elif ((${len_a} == 0)); then
printf %${len}.${len}s "${b: -$((len<len_b?len:len_b))}"
elif ((len <= 2)); then
printf %.${len}s "${a::1}${b: -1}"
else
local adj_a=$(((len_a*len+len_b-len_a)/(len_a+len_b)))
local adj_b=$(((len_b*len+len_a-len_b-1)/(len_a+len_b)))
printf "%-${adj_a}.${adj_a}s %${adj_b}.${adj_b}s" \
"$a" \
"${b: -$((len_b<adj_b?len_b:adj_b))}"
fi
}
C:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void truncat(long len, const char* a, const char* b) {
if (len <= 0) return;
unsigned long long len_a = strlen(a);
unsigned long long len_b = strlen(b);
if (!len_b)
printf("%-*.*s", (int)len, (int)len, a);
else if (!len_a)
printf("%*s", (int)len, b + (len < len_b ? len_b - len : 0));
else if (len <= 2)
printf("%.1s%.*s", a, (int)(len - 1), b + len_b - 1);
else {
unsigned long long adj_a = (len_a * len + len_b - len_a) / (len_a + len_b);
unsigned long long adj_b = (len_b * len + len_a - len_b - 1) / (len_a + len_b);
printf("%-*.*s %*s",
(int)adj_a, (int)adj_a, a,
(int)adj_b, b + (adj_b < len_b ? len_b - adj_b : 0));
}
}
int main(int argc, char** argv) {
truncat(atol(argv[1]), argv[2], argv[3]);
return 0;
}
Sample output:
$ for i in {0..20}; do printf "%2d '%s'\n" $i "$(./truncat $i stack overflow)"; done
0 ''
1 's'
2 'sw'
3 's w'
4 's ow'
5 'st ow'
6 'st low'
7 'st flow'
8 'sta flow'
9 'sta rflow'
10 'stac rflow'
11 'stac erflow'
12 'stac verflow'
13 'stack verflow'
14 'stack overflow'
15 'stack overflow'
16 'stack overflow'
17 'stack overflow'
18 'stack overflow'
19 'stack overflow'
20 'stack overflow'
Disclaimer: The arithmetic can overflow, in which case the output will be wrong (or, if you can arrange for strlen(a)+strlen(b) to be exactly 2^64 bytes, the program will SIG_FPE). I can provide an explanation for the adj_a and adj_b computations if anyone cares.
printf %.2s Silohace
truncates in bash. – Cursor