Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.
< pool.sam awk '
  /./ {printf $1}
  {printf $7+1,"\t"}
  {printf $3,"\t"}
  {
    if($2 !=16) {print "\t", "+";} else {print "\t","-";}
    {printf $4,"\t" ,length($10)+$4, "\t", "1"}
  }'

I am getting all the values, but in a weird manner. I am printing 7 values,

value1 value2 value3 value7

I want all these 7 values, separated by a TAB, in each Line.

I tried my best to figure out if to use print or to use printf Seems, I lost in that.

Kindly guide me.

share|improve this question
2  
It would help if you included sample text from pool.sam and an example of the output you are after... –  jasonwryan Oct 11 '13 at 6:32
    
value1 value2 value3 value7 are only four (4) values. your script references up to ten values ($10) –  umläute Oct 11 '13 at 6:47

2 Answers 2

up vote 2 down vote accepted

While printf is a print formatted function, print concatenates parameters.

Looks like you need to check out the printf function (or both).

In short it is:

printf <format, <parameter1>[, <parameter2>, ...] | text>

The letter % in a format denotes here comes a parameter that should be formatted as .... Format can hold special sequences like \t, \n. Printf does not terminate output by newline. If only one argument is given it is normally printed as is.


If it is a number the default formatting is "%.6g":

CODE  : printf 1.123456789
RESULT: 1.12346

If e.g. $1 is 1.123456789 it is normally treated as text, as in:

CODE  : printf $1
RESULT: 1.123456789
CODE  : printf $1+0 # Force conversion to number
RESULT: 1.12346

When you give more then one argument the first one is used as format and the rest as parameters. If to few parameters are given to fulfill the pattern the behavior is undefined.

printf "%d %s\n", 123, "hello"
         || | |    |      |
         || | |    |      +----- Parameter 2
         || | |    +------------ Parameter 1
         || | +----------------- Print new-line
         || +------------------- Print parameter 2 as string
         |+--------------------- Print literal space
         +---------------------- Print parameter 1 as digit

printf "%d %s\n", 123, "hello"
# Gives: 123 hello
printf "%d %s\n", "hello", 123
# Gives: 0 123
printf "%d %s\n", 123
# Gives undefined result (according to format one parameter is missing)

And if arguments are given without any placeholder the are discarded:

printf "%d", 123
# Gives: 123
printf "%d", 123, 22
# Gives: 123
printf "%d", 123, 22, "\t", "foo", 5566, 12.55, "\n", "blah"
# Gives: 123

The % character denotes "here is a conversion specification". If a non valid specification is given, as in one that is not defined by awk, the behavior is unspecified. Other text is treated as normal text.

printf "Hello %w", "what"
# Usually: Hello %w
# But no guarantee

printf "ABC", "DEF", "GHI"
# Result: ABC

In your code you frequently use input from file as format for printf. If those fields are not printf formats they are printed as normal text. Parameters are discarded.

# Example, say:
#     $4 = "%d %s\n"
#     $8 = "33.2"
#     $9 = "good"
printf $4, $8, $9
#
# Result: 33 good

# Say:
#     $4 = "14"
#     $8 = "33.2"
#     $9 = "good"
printf $4, $8, $9
#
# Result: 14
printf $4, "\t", $8, "\t", $9
#
# Result: 14

Your script formatted:

< pool.sam awk '
# 1.
/./ {                   # IF line not empty THEN
    printf $1           #   print field 1
}                       # ENDIF
# 2.
{
    printf $7 + 1, "\t" # printf with format = $7 + 1 and parameter <tab>
}
# 3.
{
    printf $3, "\t"     # printf with format = $3 and parameter <tab>
}
# 4.
{
    # 4.1
    if ($2 != 16) {       # IF field 2 is not 16 THEN
        print "\t", "+";  #    print <tab> + "+" (Terminate with newline)
    } else {              # ELSE
        print "\t", "-";  #    print <tab> + "-" (Terminate with newline)
    }                     # ENDIF

    # 4.2
    {
        printf $4, "\t", length($10) + $4, "\t", "1"
        # printf: pattern="field 4"
        #         parameters=<tab>, length of field 10 + field 4
    }
}
'

Say you have:

$ cat pool.sam
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

That would give you (using numbering in code above):

1.   printf "1"`                    => `1`
2.   printf 8, "\t"`                => `8`
3.   printf "3", "\t"               => `3`
4.1  print  "\t", "+"               => `<tab>+<new-line>`
4.2  printf "4", "\t", 6, "\t", "1" => `4`

Final result:

183    +
4

A rewrite that might get you somewhat on the way:

awk '
/./ {
    printf "%s%d\t%d\t", $1, $7 + 1, $3

    if ($2 != 16) {
        printf "+"
    } else {
        printf "-"
    }

    printf "%d\t%d\t1\n", $4, length($10) + $4
}
' pool.sam

The if statement, (in danger of confusing you), can also be written in one go as:

printf "%s", $2 != 16 ? "+" : "-"

Read up on format strings and printf. The align format is often very useful, as is formatting of floats etc.

right_pad=-10
printf "%*s: %5d\n", right_pad, "vix", 23
printf "%*s: %5d\n", right_pad, "popul", 336
printf "%*s: %5.2f\n", right_pad, "vidi", 42.129542488
printf "%5s %-10d +%d\n", "OK", 33, 44

Output:

vix       :    23
popul     :   336
vidi      : 42.13
   OK 33         +44

Easiest, at least I find it, is to use a script instead of command-line when playing around.

share|improve this answer
    
'code' cat $lastPartGenome.sam | awk ' function tag(){ return $7+1; } function strand(){ if($2==16) return "-"; else return "+"; } function printFields(){ if(($3 !~ /*/) && ($1 ~ /^[A-Z]/) ) { print $1"\t"tag()"\t"$3"\t"strand()"\t"$4"\t"length($10)+$4"\t""1" } } printFields() ' > $lastPartGenome.bed This is what I finally did. This helped me keep my code organized and arrange it. I was unable to understand the If syntax given above. –  Death Metal Oct 12 '13 at 0:22
    
@DeathMetal: Expanded on the answer, but had a browser-crash, so I gave up ... Anyhow to recap in short. Yes. Splitting up code can be helpful in both maintaining and understanding the code. (Though if it is performance critic – one should also benchmark.) I usually split out things that I do more then once (or if it is code I can have use for elsewhere as a function). For the if statement check out ternary operators – They can be quite helpful, especailly when it comes to printing text. –  Sukminder Oct 14 '13 at 1:34

you are running a lot of printfs for that job. why not simply do something like

cat pool.sam |\
 awk '/./ {printf $1,$7+1,"\t"$3,"\t",($2!=16)?"+","-",$4,"\t",length($10)+$4,"\t1"}}'
share|improve this answer
    
> 'cat file.sam | awk ' function tag(){ return $7+1; >} function strand(){ if($2==16) return "-"; >else return "+"; } function printFields(){ if(($3 >!~ /*/) && ($1 ~ /^[A-Z]/) ) { print $1"\t"tag()"\t"$3"\t"strand()"\t"$4"\t"length($10)+$4"\t""1" } } printFields() ' > file2.bed ' Sorry, I don't know how post code in comments. <br/> @umlaute - now it is only one. I was unable to understand if ()?: so had switched to normal/unsophisticated if. :) –  Death Metal Oct 14 '13 at 17:03
    
@DeathMetal for posting code in comments, use backquotes. as for the ()?:, this is an ordinary ternary conditional expression –  umläute Oct 14 '13 at 18:45

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.