12

Suppose I have a file like this:

$ cat a
hello this is a sentence
and this is another one

And I want to print the first two columns with some padding in between them. As this padding may change, I can for example use 7:

$ awk '{printf "%7-s%s\n", $1, $2}' a
hello  this
and    this

Or 17:

$ awk '{printf "%17-s%s\n", $1, $2}' a
hello            this
and              this

Or 25, or... you see the point: the number may vary.

Then a question popped: is it possible to assign a variable to this N, instead of hardcoding the integer in the %N-s format?

I tried these things without success:

$ awk '{n=7; printf "%{n}-s%s\n", $1, $2}' a
%{n}-shello
%{n}-sand

$ awk '{n=7; printf "%n-s%s\n", $1, $2}' a
%n-shello
%n-sand

Ideally I would like to know if it is possible to do this. If it is not, what would be the best workaround?

1
  • 3
    oh! fedorqui asked a question! Commented Aug 20, 2014 at 14:50

4 Answers 4

26

If you use * in your format string, it gets a number from the arguments

awk '{printf "%*-s%s\n", 17, $1, $2}' file
hello            this
and              this

awk '{printf "%*-s%s\n", 7, $1, $2}' file
hello  this
and    this

As read in The GNU Awk User’s Guide #5.5.3 Modifiers for printf Formats:

The C library printf’s dynamic width and prec capability (for example, "%*.*s") is supported. Instead of supplying explicit width and/or prec values in the format string, they are passed in the argument list. For example:

w = 5
p = 3
s = "abcdefg"
printf "%*.*s\n", w, p, s

is exactly equivalent to:

s = "abcdefg"
printf "%5.3s\n", s
Sign up to request clarification or add additional context in comments.

6 Comments

Splendid, yes! Do you have any source explaining this behaviour?
don't know this. +1 dude
@fedorqui Sure, it is stated here
These and the positional specifiers are my favorite underused (and under-supported) specifiers.
All I could do was sit back and click the +1 ... :-). Y'know what functionality doesn't exist that I wish did though - to be able to specify any lead character when padding. Just like you can do awk 'BEGIN{printf "%05d\n",17}' to left-pad with zeros, it'd often be convenient if you could do awk 'BEGIN{printf "%#5d\n",17}' to pad with #s or any other character. That way if you wanted a string of 5 #s you could simply do awk 'BEGIN{printf "%#5d\n",""}' instead of awk 'BEGIN{print gensub(/0/,"#","g",sprintf("%05d",""))}' or similar. Oh well there we'd go towards language bloat again..
|
6

does this count?

idea is building the "dynamic" fmt, used for printf.

kent$   awk '{n=7;fmt="%"n"-s%s\n"; printf fmt, $1, $2}' f 
hello  this
and    this

2 Comments

Good idea! Quite similar to konsolebox, only that you use "model-view-controller" pattern :)
My preferred solution out the answers. Example: git log --pretty=%ae | awk '{ n=length($1) ; if (n>l) l=n ; arr[tolower($1)]++ } END { fmt="%-"l"s: %4i\n" ; for (i in arr) printf(fmt, i, arr[i]) | "sort" }' - Meaning, calculate the max length of the git author to use in the END block printf.
4

Using simple string concatenation.

Here "%", n and "-s%s\n" concatenates as a single string for the format. Based on the example below, the format string produced is %7-s%s\n.

awk -v n=7 '{ printf "%" n "-s%s\n", $1, $2}' file
awk '{ n = 7; printf "%" n "-s%s\n", $1, $2}' file

Output:

hello  this
and    this

2 Comments

Nice! This seems to be making it. Would you mind adding some explanation for future readers?
Many thanks, I would have selected this answer if jaypal's answer did not appear. Clear and well explained, thanks!
-1

you can use eval (maybe not the most beautiful with all the escape characters, but it works)

i=15
eval "awk '{printf \"%$i-s%s\\n\", \$1, \$2}' a"

output:

hello          this
and            this

2 Comments

Yes, good one, although I was looking for something "fully awk specific".
at least it is versatile for other commands where you would like to do something similar...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.