How to Store Output from Printf with Formatting in a Variable

How to store output from printf with formatting in a variable?

echo will print each of it's arguments in order, separated by one space. You are passing a bunch of different arguments to echo.

The simple solution is to quote $A:

A=$(printf "%-40s %8s %9s  %7s" "File system" "Free" "Refquota" "Free %")
echo "$A"

How to store output of two printf into a variable in c

As of now you are overwriting the buffer everytime with latest snprintf call.

You need to consider last number of bytes written which snprintf returns.

Example:

int numBytes = 0;

for (c = 1; c <= 10; c++)
{
numBytes += snprintf(buffer+numBytes, sizeof(buffer)-numBytes, "%d", c+2);
if (c%2) {
numBytes += snprintf(buffer+numBytes, sizeof(buffer)-numBets, "%d", c+2);
}
}

how to store printf into a variable?

You can do it with sprintf, but not alone (safely). On a sane system, use snprintf twice, once to find out the size to use and the second time to actually do it. This depends on snprintf returning the number of characters needed when it runs out of room. Linux, BSD, and C99-compatible systems do this; Windows typically does not. In the latter case, you'll need to allocate an initial buffer and allocate a bigger one if snprintf fails (in a loop until snprintf succeeds). But on C99, the following will work:

char *buf;
size_t sz;
sz = snprintf(NULL, 0, "select key from answer WHERE key = %s LIMIT 5;", tmp);
buf = (char *)malloc(sz + 1); /* make sure you check for != NULL in real code */
snprintf(buf, sz+1, "select key from answer WHERE key = %s LIMIT 5;", tmp);

However, for building SQL, it's far better to use prepared statements. They avoid SQL injection vulnerabilities (and frequently the need for sprintf). With them, you would prepare the statement "select key from answer where key = ? limit 5;", and then execute it with the parameter tmp. The SQL engine puts in the string and removes the need to make sure it's properly escaped first.

Can I assign a printed output into a variable?

If you just want to output single characters, then putting data in a char buffer, as the other answer suggests, is the right answer. It is easy, it is fast, it is nothing but goodness.

If, however, you need to format different types to strings, and you want to save those strings in a buffer, then you want to look at sprintf or the safer snprintf. Using this function (it is part of C99 so it should be available everywhere by now), you can write formatted strings into a buffer.

Of course, you risk writing outside the bounds of the buffer if you are not careful, which is why the snprintf function is better than sprintf, and if you write to a buffer repeatedly, you need to keep track of both where the next data should be written, and how long the buffer is. The former is easy to keep track of, because snprintf returns how much it wrote (excluding the zero termination), so you can just update a cursor with that amount each time you write.

Using snprintf with a buffer, your example program could look like this:

#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

struct buf
{
size_t cursor, len;
char data[];
};

struct buf *new_buf(size_t len)
{
struct buf *buf = malloc(offsetof(struct buf, data) + len);
assert(buf); // handle allocation error
buf->cursor = 0;
buf->len = len;
return buf;
}

int main(void)
{
char n[] = "2445";
struct buf *buf = new_buf(sizeof n);

for (size_t i = 0; i < sizeof n; i++)
{
buf->cursor +=
snprintf(buf->data + buf->cursor, // where to write
buf->len - buf->cursor, // how much you can write (snprintf takes care of '\0')
"%c", n[i] + 1); // what to write
}

printf("result = `%s`\n", buf->data);

free(buf);
return 0;
}

After each write with snprintf, buf->data + buf->cursor points at where snprintf put the zero terminal byte, so if we write the next data starting at that address, then we add one serialised data value after the next. You can modify the formatting string if you want spaces or commas or anything else between the data.

Of course, with that code, if you run out of buffer space, you have a problem. It is not that snprintf will write out of bounds (that is what the n in snprintf does better than sprintf), but it simply won't write all the data you give it. It will only write to the end of the buffer and no more.

If you want to ensure that you get all the data, you have to grow the buffer if it fills out.

We are lucky that we can get the size of a formatted string if we call it with zero for the maximum length (where we used buf->len - buf->cursor above). If we do that, and we don't need to provide a buffer if we do, then we get the length we need back. So, before we write to the buffer, we can ask for the necessary length, and then we can extend the buffer to get enough space.

#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX(A, B) (((A) > (B)) ? (A) : (B))

struct buf
{
size_t cursor, len;
char data[];
};

struct buf *resize_buf(struct buf *buf, size_t len)
{
// don't allow len == 0; it will mess up doubling of lengths.
len = len ? len : 1;

struct buf *new_buffer = realloc(buf, offsetof(struct buf, data) + len);
assert(new_buffer);

// if it's a new buffer, set the cursor (otherwise it is already set)
new_buffer->cursor = buf ? new_buffer->cursor : 0;
new_buffer->len = len;
return new_buffer;
}

struct buf *new_buf(size_t len)
{
return resize_buf(0, len);
}

int main(void)
{
char n[] = "2445";
struct buf *buf = new_buf(0); // empty now, but we will resize

for (size_t i = 0; i < sizeof n; i++)
{
// I've changed the formatting string to %d, so now you get the ASCII
// codes plus one. They are no longer a single character long.
// the +1 after snprintf() is for the zero sentinel '\0'
size_t needed = snprintf(0, 0, "%d ", n[i] + 1) + 1;
if (needed > buf->len - buf->cursor)
{
buf = resize_buf(buf, MAX(buf->len + needed, 2 * buf->len)); // double the length
}
buf->cursor +=
snprintf(buf->data + buf->cursor, // where to write
buf->len - buf->cursor, // how much you can write (snprintf takes care of '\0')
"%d ", n[i] + 1); // what to write
}

printf("result = `%s`\n", buf->data);

free(buf);
return 0;
}

I'm growing the buffer by factors of two to get a linear time growth, if you grow it only with the needed size each time it can end up with a quadratic running time. Other than that, there isn't much complicated in it; we ask for how much space we need, then we make sure that we have it by growing the buffer if needed, and then we write to the buffer the same as before.

It isn't a particularly nice solution, though. We absolutely have to make sure that the formatting string we create in the first and the second call to snprintf is the same, or we can really mess up, and the details of the buffer implementation are fundamentally exposed to the user. It is better to wrap it up in a function.

If we want to handle general formatting strings, we need a variadic function, and they can look a bit weird if you are not used to them. But they work like this: you use ... as the last argument to your function, then you can get a pointer to the additional arguments with va_start() and you need to free some data structure that holds the arguments again with va_end().

For our purposes, we do not need to do anything special with the arguments, because we can just call vsnprintf with them. That function is the equivalent of snprintf that takes these structures instead of arguments. I think vsnprintf is from C99, so you should also have it, but I admit that it is possible that it isn't there until C11 (but you should really also have that).

We need to call vsnprintf twice, and we need to set up the arguments and free them again before each call, but other than that there is nothing to it.

#include <assert.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX(A, B) (((A) > (B)) ? (A) : (B))

struct buf
{
size_t cursor, len;
char data[];
};

struct buf *resize_buf(struct buf *buf, size_t len)
{
// don't allow len == 0; it will mess up doubling of lengths.
len = len ? len : 1;

struct buf *new_buffer = realloc(buf, offsetof(struct buf, data) + len);
assert(new_buffer);

// if it's a new buffer, set the cursor (otherwise it is already set)
new_buffer->cursor = buf ? new_buffer->cursor : 0;
new_buffer->len = len;
return new_buffer;
}

struct buf *new_buf(size_t len)
{
return resize_buf(0, len);
}

struct buf *write_to_buf(struct buf *buf, const char *restrict fmt, ...)
{
va_list args;

va_start(args, fmt);
size_t needed = vsnprintf(0, 0, fmt, args);
va_end(args);

if (needed > buf->len - buf->cursor)
{
buf = resize_buf(buf, MAX(buf->len + needed, 2 * buf->len));
}

va_start(args, fmt);
buf->cursor +=
vsnprintf(buf->data + buf->cursor,
buf->len - buf->cursor,
fmt, args);
va_end(args);

return buf;
}

int main(void)
{
char n[] = "2445";
struct buf *buf = new_buf(0); // empty now, but we will resize

for (size_t i = 0; i < sizeof n; i++)
{
buf = write_to_buf(buf, "%d ", n[i] + 1);
}

printf("result = `%s`\n", buf->data);

free(buf);
return 0;
}

This should give you an idea about how to make a buffer you can write general formatting strings to. I am making no claims that this code is stable or the right kind of interface or anything, I just whipped it up rather quickly, but it should be place to start from.

How to use a bash variable to hold the format of find's printf statement

You can store a single argument in a regular variable:

print_format="File: %p has modification time [%TY-%Tm-%Td %TH:%TM:%TS %TZ]\n"
find ./ -type f -printf "$print_format"

or you can store one or more arguments in an array:

find_options=( -printf "File: %p has modification time [%TY-%Tm-%Td %TH:%TM:%TS %TZ]\n" )
find ./ -type f "${find_options[@]}"

How To Invoke Variables To Specify Format Of printf In C Programming

Is there similar way like the above [format="%4s%4d %8s\n"] in C programming?

Is it possible
in C?

Yes, several ways to both questions.

Among them, you can use sprintf() to prepare the buffer:

char format[80] = {0};//create editable char array
int a = 12;
char buf1[] = {"this is string 1"};
char buf2[] = {"this is string 2"};

sprintf(format, "%s", "%4s%4d %8s\n");
printf(format, buf1, val, buf2);

Even closer to what you have done in your example ( format="%4s%4d %8s\n" ), you can simply define format as a string literal:

char *format = "%4s%4d %8s\n";//string literal not editable

Or, create an initialized, but editable char array

char format[] = {"%4s%4d %8s\n"};//editable, but only up to 
//strlen("%4s%4d %8s\n");
//(+ NULL, which is implied when using "...".)

Note that C also provides a built in feature to enable run-time setting of precision when outputting floating point numbers:

double val = 22.123445677890;
int precision = 3;

printf("%.*f", precision , val);

Will output 22.123

How to pass variable within printf

Your problem is that you are using single-quotes. Parameters are not expanded within single quotes.

Parameters are expanded in double-quotes, though:

printf "Are you sure you want $lrus lrus: "

Note that there's no need for a separate print; it's better to use the -p argument to read (that understands your terminal width, for one thing):

read -p "Specify lrus [default 128]: " -r lrus
read -p "Are you sure you want $lrus lrus? " -r ans


Related Topics



Leave a reply



Submit