1

I'd like to start a long, complex CPU and IO heavy command-line job to be done in background while I'm using the PC. It will hinder responsiveness of the system if I run it with normal priority. How do I start a shell (under which the job will be executed) the way all the processes ran from within it and processes they run would have low priority?

Ivan
  • 17,368
  • 35
  • 93
  • 118
  • Possibly related: [Nice and child processes](https://unix.stackexchange.com/questions/37896/nice-and-child-processes) – steeldriver Sep 14 '19 at 01:01

1 Answers1

3

To execute a command in a process with lower priority whether that command is a shell or your heavy command (which itself could also be a shell script), on Linux you can do:

nice ionice -c idle the-command and its arguments

nice is standard, ionice is Linux-specific.

To run some shell code, use sh -c as the command:

nice ionice -c idle sh -c '
  for i in foo bar; do
    heavycmd "$i" > "$i.log"
  done'

nice alone increases the niceness by 10, you can specify a different increment with the -n option.

In the zsh shell, you can set the bgnice option (on by default when interactive) so that all commands run in background have their niceness increased by 5.

In the (t)csh shell, nice is a builtin which can also change the niceness of the shell (beware that the syntax is different from the nice standard command (nice +10 cmd to specify arbitrary niceness (not increment!)) and the default niceness is 4).

In shells that don't support changing their own niceness by themselves, you can use renice instead. Beware that renice -n 5 "$pid" is currently required by POSIX to decrease the niceness of the process of id $pid by 5, but that's not what happens in any implementation I know and is quite obviously a bug in the POSIX specification¹. In practice, it either sets the niceness to 5² or increases it by 5.

In practice, renice -n 20 "$pid" assuming the niceness was not negative in the first place would set the niceness to the highest value at least on Linux.

Note that nice (introduced in Unix V4 in the mid-70s) initially didn't take any number argument. A numeric argument was added independently in Unix V7 and in csh (BSD based on V6) but done differently. In V7, nice -5 cmd increased the niceness by 5 while in csh (as seen above), that would set it to -5. renice was initially from BSDs and was consistent with csh's nice (renice +5 "$pid" to set the niceness to 5).

That history explains why nowadays, outside of csh, nice -5 increases niceness and renice -5 decreases it. I suspect -n is a POSIX invention (like for head -n) introduced to get rid of the option names with leading + and to try and come with a clean API (niceness values are also not portable, so it makes more sense to deal with increments).

The I/O niceness of other arbitrary processes can also be changed with ionice and its -p option.

So from within the shell (Bourne-like shells here), you can change the niceness of the process that executed the shell interpreter with:

renice -n 20 "$$"
ionice -c idle -p "$$"

Or to change the niceness of the current subshell:

(
  pid=$(sh -c 'echo "$PPID"')
  renice -n 20 "$pid"
  ionice -c idle -p "$pid"

  # do stuff in the subshell with lower priority / higher niceness
)

In the bash shell, you can also get the current subshell pid with $BASHPID and in zsh with $sysparams[pid] (after zmodload zsh/system). Beware that the ksh93 shell doesn't implement subshell environments with child processes, so the above would affect the niceness globally there.


¹ That was introduced in SUSv3, the previous version (which also specified the original renice API (as obsolete)) correctly said that a positive value decreased the priority, not niceness

² like in the util-linux implementation. That is a bug. -n was added in 2009 for POSIX conformance, but maintainers failed to realise that -n takes an increment in the POSIX specification. The help message since 2010 does refer to an increment, but that's not what happens.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501