Reputation: 56915
How can I pad each line of a file to a certain width (say, 63 characters), padding with spaces if need be?
For simplicity, let’s assume that all lines are guaranteed to be less than 63 characters.
I use Vim and would prefer a way to do it there, where I can select the lines I wish to apply the padding to, and run some sort of a printf %63s current_line
command.
However, I’m certainly open to using sed, awk, or some sort of linux tool to do the job too.
Upvotes: 26
Views: 18456
Reputation: 28954
In Vim, I would use the following command:
:%s/$/\=repeat(' ',64-virtcol('$'))
The use of the virtcol()
function here, as opposed to the col()
one,
is guided by the necessity to properly handle tab characters as well as
multibyte non-ASCII characters that might occur in the text.)
To compute the length of the longest line in the buffer (plus 1) — to be used in place of 64 — one can use the following command:
:let m = max(map(range(1, line('$')), 'virtcol([v:val,"$"])'))
The range of lines can be narrowed, if necessary. For example, to
do the same for the visually selected lines, one can provide map()
with the range(line("'<"), line("'>"))
argument, instead (see
:help line()
, :help '<
). (Notice that in the latter case, to
run the command interactively while in Visual mode, one will need
to delete the '<,'>
prefix that Vim will automatically put in the
command line once :
is typed.)
To do both steps in a single command invocation, one can join the two
commands with |
. For instance, to pad visually selected lines
(or the lines that were in the last Visual selection), run:
:let m=max(map(range(line("'<"),line("'>")),'virtcol([v:val,"$"])')) | '<,'>s/$/\=repeat(' ',m-virtcol('$'))
If used frequently, this combined command can can be bound to a key mapping.
Here is an example implementation of a Visual-mode key mapping to be added
to the .vimrc
file:
vnoremap <silent> <leader><bar> :call RightPadLines(' ', +0)<cr>
func! RightPadLines(char, extra) range
let m = max(map(range(a:firstline, a:lastline), 'virtcol([v:val, "$"])'))
let m += a:extra
sil exec $'{a:firstline},{a:lastline}' 's/$/\=repeat(a:char, m-virtcol("$"))'
endfunc
The keyboard shortcut here is the leader key (see :help mapleader
) followed
by the |
key, but, of course, any combination can be used instead.
Upvotes: 15
Reputation: 3451
Another Perl solution:
$ perl -lne 'printf "%-63s\n", $_' file
Upvotes: 2
Reputation: 16750
With sed, without a loop:
$ sed -i '/.\{63\}/!{s/$/ /;s/^\(.\{63\}\).*/\1/}' file
Be sure to have enough spaces in the 1st substitution to match the number of space you want to add.
Upvotes: 2
Reputation: 21
It looks like you are comfortable using vim, but here is a pure Bash/simple-sed solution in case you need to do it from the command line (note the 63 spaces in the sed substitution):
$ sed 's/$/ /' yourFile.txt |cut -c 1-63
Upvotes: 2
Reputation: 58430
This might work for you:
$ sed -i ':a;/.\{63\}/!{s/$/ /;ba}' file
or perhaps more efficient but less elegant:
$ sed -i '1{x;:a;/.\{63\}/!{s/^/ /;ba};x};/\(.\{63\}\).*/b;G;s//\1/;y/\n/ /' file
Upvotes: 3
Reputation: 246827
Just for fun, a Perl version:
$ perl -lpe '$_ .= " " x (63 - length $_)'
Upvotes: 3