1
< 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.

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

2 Answers 2

3

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"}}'
2
  • > '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. :) Oct 14, 2013 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, 2013 at 18:45
2

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.

2
  • '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. Oct 12, 2013 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.
    – Runium
    Oct 14, 2013 at 1:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .