jack
jack

Reputation: 101

Difference in newlines in output between awk's printf and sprintf

Gawk manual says about sprintf: "Return (without printing) the string that printf would have printed out..."

Here is the printf output:

awk '{ printf "%s", $0 }' <<< 'line1
line2'
line1line2%

However, sprintf seems to preserve newlines:

awk '{ my_var=sprintf("%s", $0); print my_var }' <<< 'line1
line2'
line1
line2

(The same with BSD and GNU awk.)

Why is it so?

How do I put in a variable the newline-stripped content this way, without using RS/ORS/sub?

Upvotes: 0

Views: 705

Answers (5)

RARE Kpop Manifesto
RARE Kpop Manifesto

Reputation: 2801

if u just wanna concat it all without \n :

% jot 30 | mawk _^_ ORS=
123456789101112131415161718192021222324252627282930%  # "...%" = no trailing \n

To add back 1 more trailing newline, it's easier via the pipe :

jot 30 | gawk // ORS= | nawk $$
123456789101112131415161718192021222324252627282930

another way to add back the trailing new line while stripping all input inewlines would be like :

mawk2 ++NF OFS= RS= FS='\412'  
123456789101112131415161718192021222324252627282930

if u wanna convert vertical input to horizontal :

nawk NF=NF FS='\n' RS= 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

horizontal without trailing newline :

gawk 8 ORS=' ' 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30%

Upvotes: 0

Ed Morton
Ed Morton

Reputation: 203512

Regarding sprintf seems to preserve newlines - no, awk consumes the newline when it reads the record. In:

awk '{ my_var=sprintf("%s", $0); print my_var }' <<< 'line1
line2'

$0 never contains a newline and so the output of that sprintf doesn't contain a newline. The print command adds a newline when outputting my_var. If you did:

print "<" my_var ">"

then you'd see that my_var doesn't contain a newline, the newline appears after the >, not before it.

I'm saying newline above but it's really whatever value RS has on input and ORS on output, they're both just newline by default.

Regarding How do I put in a variable the newline-stripped content this way - that's already what it contains. If you want my_var to then be output without a newline being appended then do either this:

printf "%s", my_var

or this:

ORS=""; ...; print my_var

Upvotes: 2

James Brown
James Brown

Reputation: 37404

If you feed awk (2 records of) data with a newline in the middle, ie.:

<<<'line1
line2'

awk is going to process the input record by record (notice the NR in code, don't mind the () after printf:

$ awk '{ printf("%s %s", NR, $0) }' <<< 'line1
line2'
1 line12 line2$

or

$ awk '{ print sprintf("%s %s", NR, $0) }' <<< 'line1
line2'
1 line1
2 line2
$

In the former printf didn't produce newline after either of the records, in the latter print did.

If you want to preserve the newline (between records), read the whole data in at once without processing the newlines (well, this does involve using RS):

$ awk -v RS="^$" '{ printf("%s %s", NR, $0) }' <<< 'line1
line2'
1 line1
line2
$

If you are unable to use the RS, you need to parse the input yourself. Sample data, cat file:

line1
line2 \\
line3 \
line4
line5

\ marks to attach 2 records, \\ is a backslash:

$ awk '{
    if(/[^\\]\\$/) {                      # if ends in one \
       b=b substr($0,1,length($0)-1) ORS  # append to buffer b
       next                               # on to next record
    }
    $0=b $0                               # prepend buffer to record
    gsub(/\\\\/,"\\")                     # \\s to \s
    print sprintf("%s %s", ++c, $0)       # output, NR replace with c 
    b=""                                  # empty the buffer
}' file

Output:

1 line1
2 line2 \
3 line3 
line4
4 line5

Upvotes: 1

David C. Rankin
David C. Rankin

Reputation: 84561

If You Want To Remove the '\n'

If you want to strip the newline, then sed makes that easy:

$ sed '/[\]/{N;s/\n//}' <<< 'line1 \
line2'
line1 \line2

Or you can use awk as:

$ awk '/\\$/ {line = line $0; next} { print line $0; line = ""}' <<< 'line1 \
line2'
line1 \line2

Where you simply concatenate lines ending in \ and then output all of the concatenated lines along with the current line for the first line not ending in '\' and reset the variable you are accumulating the lines in (line above).

You can handle trailing whitespace between the '\' and end of line by adding /\\[[:blank:]]*$/ to your Regex.

Let me know if I missed your intent and I'm happy to help further.

Upvotes: 2

Daweo
Daweo

Reputation: 36450

How do I put in a variable the newline-stripped content this way, without using RS/ORS/sub?

Use sprintf return value(s) as argument(s) to printf, consider following example, let file.txt content be

12.12 14.14 16.16

then

awk '{x=sprintf("%d",$1);y=sprintf("%d",$2);z=sprintf("%d",$3)}END{printf "%s%s%s",x,y,z}' file.txt

gives output

121416

(without trailing newline)

(tested in GNU Awk 5.0.1)

Upvotes: 1

Related Questions