You are not logged in.

#1 2015-07-10 14:54:29

randomguy
Member
Registered: 2007-06-19
Posts: 101

dash printf and format string "%b" in particular

Having a go at a script that I want to run in a dash shell as a learning experience. A part of it passes a file name to vims :w command, so i need the file name escaped in case it contains spaces.

I was fairly surprised how the built-in printf "%b" behaves in dash. Reading the dash manual page I understand that "%b" would do the same thing as "%q" in bash. So my question is do I have a mental block or is this really odd and undocumented behaviour?

Some examples with the output I get:
1)

someString='some string with spaces' # Defined like that for all following printf calls
printf "%b" $someString

Gives:

somestringwithspaces

2) Double quotes help:

printf "%b" "$someString"

Gives:

some string with spaces

3) This works an I don't quite understand why because the documentation reads different:

printf "%b\ " "$someString"

Gives:

some\ string\ with\ spaces\ 

Somebody with more shell knowledge has some insight on this? Particularly an explanation of why the last command works would be appreciated.

Edit: added numbering for clarity.
Edit: output of example 3 was wrong.

Last edited by randomguy (2015-07-15 10:08:07)

Offline

#2 2015-07-10 15:33:31

respiranto
Member
Registered: 2015-05-15
Posts: 479
Website

Re: dash printf and format string "%b" in particular

If you write

printf "%b" $someString

this is in this case equivalent to

printf "%b" some string with spaces

Every space-separated word of $someString is a separate argument - not containing spaces - and is thus treated separately.

If you put the string in quotes instead, the shell (doesn't matter which) will provide printf with the whole string as one argument, which does contain the spaces.


Edit: Appended:

randomguy wrote:

This works an I don't quite understand why because the documentation reads different:

printf "%b\ " "$someString"

Gives:

some\ string\ with\ spaces

Sure the documentation says this? Where?
This is exactly what should happen, if you were running the program without quotes around $someString.

Last edited by respiranto (2015-07-10 15:39:40)

Offline

#3 2015-07-10 16:26:22

randomguy
Member
Registered: 2007-06-19
Posts: 101

Re: dash printf and format string "%b" in particular

Thanks for your reply. It dawned on me why example 1) and 2) behave like they do shortly after posting.

But 3) is still odd if read the manual page of dash. It gives me the impression that the command in 2) would produce the output in 3).
Why is adding a escaped space in the format argument leading to spaces from argument to be displayed escaped? Does it work like a list for characters to be escaped? A format string like

"%b\ \n"

would imply to escape all spaces and newlines from argument but not for example hard tabs?

From man dash:

     printf format [arguments ...]
            printf formats and prints its arguments, after the first, under control of the format.  The format is a character string which contains three
            types of objects: plain characters, which are simply copied to standard output, character escape sequences which are converted and copied to the
            standard output, and format specifications, each of which causes printing of the next successive argument.

Subsection for %b (still man dash of course):

            b           Characters from the string argument are printed with backslash-escape sequences expanded.
                        The following additional backslash-escape sequences are supported:

                        \c      Causes dash to ignore any remaining characters in the string operand containing it, any remaining string operands, and any
                                additional characters in the format operand.

                        \0num   Write an 8-bit character whose ASCII value is the 1-, 2-, or 3-digit octal number num.

Edit: formatting

Last edited by randomguy (2015-07-10 16:32:15)

Offline

#4 2015-07-10 16:44:45

progandy
Member
Registered: 2012-05-17
Posts: 5,193

Re: dash printf and format string "%b" in particular

You cannot specify any options after %b. %b is the same as %s, except that escape sequences in the string are interpreted.

$ printf "%s\n" 'foo\nbar \0101'
foo\nbar \0101
$ 
$ printf "%b\n" 'foo\nbar \0101'
foo
bar A
$ 

Now to your example:

$ printf "%b\ \n" foo bar
foo\ 
bar\ 
$ 

This is defined as follows:

The format string is reused as often as necessary to satisfy the arguments.  Any extra format specifications are evaluated with zero or the null string.

That means, print the first argument with slash expansion, then print a slash, a space, and finally a newline. Since there are more arguments than placeholders, repeat the pattern, so print again slash expanded argument, slash, space, newline.

Last edited by progandy (2015-07-10 16:49:10)


| alias CUTF='LANG=en_XX.UTF-8@POSIX ' |

Offline

#5 2015-07-10 18:02:18

respiranto
Member
Registered: 2015-05-15
Posts: 479
Website

Re: dash printf and format string "%b" in particular

I think, there is one simple misunderstanding:
You, randomguy, think, printf modifies the argument(s), i.e. $someString and then prints them/it.

However the truth is, that printf takes the first argument, the format string, as base, then replaces the so called conversion specifications, i.e. everything that begins with a '%'-sign with arguments specified after the first and finally prints the modified first argument.
That, at least is how it works in C, where the number of arguments must be the same as the number of conversion specifications.

The executable shell-command printf however does not have such a restriction. In case there are more conversion specifications, they are discarded and in case there are more arguments than conversion specifications, the latter ones will be reused - in the same order.

Last edited by respiranto (2015-07-10 18:04:52)

Offline

#6 2015-07-12 04:45:02

severach
Member
Registered: 2015-05-23
Posts: 192

Re: dash printf and format string "%b" in particular

Better run that last command again. I don't get the same result. I have an extra backslash on the end.

# export someString='some string with spaces'
# dash
$ type printf
printf is a shell builtin
$ printf "%b\ " "$someString"
some string with spaces\ $
$ printf "%b\ " $someString
some\ string\ with\ spaces\ $

# bash
$ type printf
printf is a shell builtin
$ printf "%b\ " "$someString"
some string with spaces\ $
$ printf "%b\ " $someString
some\ string\ with\ spaces\ $

# zsh
$ type printf
printf is a shell builtin
$ printf "%b\ " "$someString"
some string with spaces\ %   
$ printf "%b\ " $someString
some string with spaces\ %     
# Check out that zsh auto quoting

$ /usr/bin/printf "%b\ " "$someString"
some string with spaces\ % 

Only the format string of printf interprets escape codes. %b can make any of the rest of them interpret escape codes as desired.

# dash
$ printf "foo\nbar%s\n" "alice\nbob"
foo
baralice\nbob
$ printf "foo\nbar%b\n" "alice\nbob"
foo
baralice
bob
$

Offline

#7 2015-07-15 10:18:32

randomguy
Member
Registered: 2007-06-19
Posts: 101

Re: dash printf and format string "%b" in particular

Thank you all for your insights and help! It's true I had a wrong idea of how printf processes its arguments, thanks to respiranto for the explanation.

Also, severach, you were right the output of 3) was just not right, thanks for pointing that out and especially for the example with %s and %b.

Offline

Board footer

Powered by FluxBB