ps is defined in the procps package in Linux.
There is the code handling the -c and -l flags and priority:
if(format_modifiers & FM_c){
PUSH("pri"); PUSH("class");
}else if(format_flags & FF_Ul){
PUSH("ni");
if(personality & PER_IRIX_l) PUSH("priority");
else /* is this good? */ PUSH("opri");
}
So, if you use -c, you get the pri field.
If you use -l, you either get the priority (IRIX like) or the opri (is this good? flag)
In other words, you're not looking at the same data and this is why you get different results.
In the display.c file we see this comment:
// "PRI" is created by "opri", or by "pri" when -c is used.
//
// Unix98 only specifies that a high "PRI" is low priority.
// Sun and SCO add the -c behavior. Sun defines "pri" and "opri".
// Linux may use "priority" for historical purposes.
So you should use -o opri instead of -o pri on your command line.
To compare these priorities, you can use the -o command line option with:
ps -e -o pri,opri,intpri,priority,ni,pcpu,pid,comm | less
There are actually a few more priorities... Here is the code that displays those columns. It's always using the pp->priority value, it just changes the sign or adds/subtract a number to it. The only direct one is priority ("Pure Linux priority").
// legal as UNIX "PRI"
// "priority" (was -20..20, now -100..39)
static int pr_priority(char *restrict const outbuf, const proc_t *restrict const pp){ /* -20..20 */
return snprintf(outbuf, COLWID, "%ld", pp->priority);
}
// legal as UNIX "PRI"
// "intpri" and "opri" (was 39..79, now -40..99)
static int pr_opri(char *restrict const outbuf, const proc_t *restrict const pp){ /* 39..79 */
return snprintf(outbuf, COLWID, "%ld", 60 + pp->priority);
}
// legal as UNIX "PRI"
// "pri_foo" -- match up w/ nice values of sleeping processes (-120..19)
static int pr_pri_foo(char *restrict const outbuf, const proc_t *restrict const pp){
return snprintf(outbuf, COLWID, "%ld", pp->priority - 20);
}
// legal as UNIX "PRI"
// "pri_bar" -- makes RT pri show as negative (-99..40)
static int pr_pri_bar(char *restrict const outbuf, const proc_t *restrict const pp){
return snprintf(outbuf, COLWID, "%ld", pp->priority + 1);
}
// legal as UNIX "PRI"
// "pri_baz" -- the kernel's ->prio value, as of Linux 2.6.8 (1..140)
static int pr_pri_baz(char *restrict const outbuf, const proc_t *restrict const pp){
return snprintf(outbuf, COLWID, "%ld", pp->priority + 100);
}
// not legal as UNIX "PRI"
// "pri" (was 20..60, now 0..139)
static int pr_pri(char *restrict const outbuf, const proc_t *restrict const pp){ /* 20..60 */
return snprintf(outbuf, COLWID, "%ld", 39 - pp->priority);
}
// not legal as UNIX "PRI"
// "pri_api" -- match up w/ RT API (-40..99)
static int pr_pri_api(char *restrict const outbuf, const proc_t *restrict const pp){
return snprintf(outbuf, COLWID, "%ld", -1 - pp->priority);
}
So we see
- "priority" -- direct Linux priority (-100 to 39)
- "intpri", "opri" -- Linux priority + 60 (-40 to 99)
- "pri_foo" -- Linux priority - 20 (-120 to 19)
- "pri_bar" -- Linux priority + 1 (-99 to 40)
- "pri_baz" -- Linux priority + 100 (1 to 140)
- "pri" -- 39 - Linux priority (0 to 139, REVERSED)
- "pri_api" -- -1 - Linux priority (-40 to 99, REVERSED)
The last two ("pri" and "pri_api") are considered "illegal" under Unix.
As for where this data comes from, it is found in the /proc/<id>/stat file. The file is read and the one line of text is parsed by the following sscanf() call after skipping the process ID and name (which is between parenthesis.)
We see that one parameter is &P->priority. So the 18th parameter (16th after skipping the ID and name), starting at 1.
num = sscanf(S,
"%c "
"%d %d %d %d %d "
"%lu %lu %lu %lu %lu "
"%Lu %Lu %Lu %Lu " /* utime stime cutime cstime */
"%ld %ld "
"%d "
"%ld "
"%Lu " /* start_time */
"%lu "
"%ld "
"%lu %"KLF"u %"KLF"u %"KLF"u %"KLF"u %"KLF"u "
"%*s %*s %*s %*s " /* discard, no RT signals & Linux 2.1 used hex */
"%"KLF"u %*u %*u "
"%d %d "
"%lu %lu",
&P->state,
&P->ppid, &P->pgrp, &P->session, &P->tty, &P->tpgid,
&P->flags, &P->min_flt, &P->cmin_flt, &P->maj_flt, &P->cmaj_flt,
&P->utime, &P->stime, &P->cutime, &P->cstime,
&P->priority, &P->nice,
&P->nlwp,
&P->alarm,
&P->start_time,
&P->vsize,
&P->rss,
&P->rss_rlim, &P->start_code, &P->end_code, &P->start_stack, &P->kstk_esp, &P->kstk_eip,
/* P->signal, P->blocked, P->sigignore, P->sigcatch, */ /* can't use */
&P->wchan, /* &P->nswap, &P->cnswap, */ /* nswap and cnswap dead for 2.4.xx and up */
/* -- Linux 2.0.35 ends here -- */
&P->exit_signal, &P->processor, /* 2.2.1 ends with "exit_signal" */
/* -- Linux 2.2.8 to 2.5.17 end here -- */
&P->rtprio, &P->sched /* both added to 2.5.18 */
);
There is an example of the data that the libprocps reads:
$ cat /proc/1/stat
1 (systemd) S 0 1 1 0 -1 4194560 188421 1692322137 105 191899 1093 466 35079020 6527486 20 0 1 0 2 341475328 1402 18446744073709551615 1 1 0 0 0 0 671173123 4096 1260 0 0 0 17 2 0 0 3606 0 0 0 0 0 0 0 0 0 0
So process 1 has a Linux priority of 20. When converted to a pri (as with your -o pri command line option), it becomes 39 - 20 = 19.
When using the -l command line option, it uses the opri instead. This means 20 + 60 = 80.
So comparing those two commands lines is completely wrong since in one case the priority is REVERSED and not the other. Now, don't get me wrong... I know there is pretty much nothing about that information in the documentation of ps. It's up to you to know how ps works, I guess. Luckily, under Linux we have the source code to the rescue!
I hope you don't need to make your script compatible with a kernel other than Linux...