7

How can I include a variable in a printf expression?

Here's my example:

printf "%${cols}s", $_;

Where $cols is the number of columns and $_ is a string.

The statement results in an "Invalid conversion" warning.

The problem ended up being that I forgot to chomp the variable. Gah. Thanks everyone.

4
  • 1
    Can you please post the full warning text? Commented Feb 17, 2010 at 21:09
  • I think the problem is that I am getting the number of columns from the user (STDIN). Here is the full error: Invalid conversion in printf: "%\012" at column2 line 28, <STDIN> line 3 (#1) (W printf) Perl does not understand the given format conversion. See perfunc/sprintf. This is with $cols = 20. But it may actually be $cols = "20" Commented Feb 18, 2010 at 14:11
  • So the answer ended up being that I need to chomp the number of columns because it was user input from STDIN and had a newline on the end. Commented Feb 18, 2010 at 14:16
  • When you run into these sorts of problems, look at string you are trying to use to ensure it's what you think it is: print "%${cols}s". Most of your programming time will probably be checking values to see that they are what you think they are. Commented Feb 22, 2010 at 0:06

6 Answers 6

11

Your interpolated variable $cols looks like its supposed to be a number, say 10, so

"%${cols}s"

should interpolate and be equivalent to

"%10s"

which is a valid format string.

If however $cols was something other than a number or valid format string, you'd get the warning.

For example, if:

$cols = "w";

that would result in "%ws" as a format string - giving the error you quote:

Invalid conversion in printf: "%w"

Valid format information can be found here.

Sign up to request clarification or add additional context in comments.

1 Comment

+1 This is relevant, as it correctly shows the error message. I think I got what the actual problem was, but it's impossible to know without hearing from the OP.
9

I figured out your specific problem. Your code is correct. However, I suppose $cols might be a number read from user input, say like this:

my $cols = <STDIN>;

This works, and in numeric context $cols will appear to be a number, but the problem is that $cols isn't appearing in numeric context here. It's in string context, which means that instead of expanding to "%5s", your format string expands to "%5\ns". The newline there is mucking up the format string.

Change the code where you read $cols to this:

chomp(my $cols = <STDIN>);

See the documentation on chomp, as you may want to use it for other input reading as well.

1 Comment

This was the answer. I had a new line appended to the end of the user input where the user had input the number of columns. MANY THANKS! :)
6

Always use * in your format specifier to unambiguously indicate variable width! This is similar to the advice to use printf "%s", $str rather than printf $str.

From the perlfunc documentation on sprintf:

(minimum) width

Arguments are usually formatted to be only as wide as required to display the given value. You can override the width by putting a number here, or get the width from the next argument (with *) or from a specified argument (with e.g. *2$):

printf '<%s>', "a";       # prints "<a>"
printf '<%6s>', "a";      # prints "<     a>"
printf '<%*s>', 6, "a";   # prints "<     a>"
printf '<%*2$s>', "a", 6; # prints "<     a>"
printf '<%2s>', "long";   # prints "<long>" (does not truncate)

If a field width obtained through * is negative, it has the same effect as the - flag: left-justification.

For example:

#! /usr/bin/perl

use warnings;
use strict;

my $cols = 10;
$_ = "foo!";
printf "%*s\n", $cols, $_;
print "0123456789\n";

Output:

      foo!
0123456789

With the warnings pragma enabled, you'll see warnings for non-numeric width arguments.

Comments

3

Your current method should work

perl -e'my $cols=500; $_="foo"; printf "%${cols}s\n\n", $_;'

2 Comments

You should test it with -Mstrict and -Mwarnings, but it does work. Curious why the OP is getting warnings now...
I did before I posted ;) I didn't want it to look like this answer took me more than 5 seconds. Testing this stuff is really simple with Perl, I really don't even have to cut that stuff out to drive my point home.
1

The following seems to work for me:

#!/bin/perl5.8 -w
use strict;
my $cols = 5;
my $a = "3";
printf "%${cols}d\n", $a;

yields

28$ ./test.pl
    3

29$ 

Comments

1

I cannot reproduce your problem. The following code works fine:

use strict;
use warnings;

my $cols=40;
while (<>) {
    printf "%${cols}s\n", $_;
}

It prints any input line using at least 40 columns of width.

Comments

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.