You are not logged in.
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
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:
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
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
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
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
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
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