I'm on Ubuntu 18.04 64bit, I'm trying to save the resolution of my 2 screens so I'm trying to put a script who uses xrandr to set it (if I execute the script from the terminal it works), so I put it in crontab (by using this syntax: sudo crontab - e and by adding as last line this code: @reboot /avvio/; ./screen.sh) but it doesn't do nothing, the script works and I'm sure it gets executed because I tried adding other things to the script and they work, if I launch it from the terminal it also sets the resolution but it doesn't set it at startup. The code of screen.sh is

xrandr --newmode "1680x1050_60.00"  146.25  1680 1784 1960 2240  1050 1053 1059 1089 -hsync +vsync
xrandr --addmode VGA-1 "1680x1050_60.00"
xrandr --output VGA-1 --mode 1680x1050_60.00 --pos 1920x0 --output HDMI-1 --primary --pos 0x0

You can use Startup Applications

xrandr doesn't require sudo permissions so you can place your script in Startup Applications. Generally only use cron boot scripts for jobs requiring sudo powers.

New Script

The original answer was a reference. This new answer uses the reference and takes out unnecessary code. Then OP code is added to the bottom of the new answer.

Use sudo -H gedit /etc/cron.d/start_screen and insert these lines:

@reboot   root    /usr/local/bin/screen.sh

Save the file. There is no need to mark it as executable.

Note: The PATH command is very important as cron has limited PATH knowledge and may not find the commands such as /usr/bin/who or /usr/bin/awk.

Contents of /usr/local/bin/screen.sh

#! /bin/bash

# NAME: screen.sh
# PATH: /usr/local/bin
# DESC: Set screen to brightness .5 to confirm it can be done.
#       Ask Ubuntu question: https://askubuntu.com/questions/1102389/xrandr-not-working-on-crontab/1102436?noredirect=1#comment1817209_1102436
# CALL: called from `/etc/cron.d/start-screen`
# DATE: Created December 17, 2018.


export DISPLAY=:0       # For xrandr commands to work.

# wait until user signs on to get .Xauthority file settings.
while [[ $UserName == "" ]]; do
    sleep 2
    logger "screen.sh slept 2 seconds waiting for login"
    UserName="$(who -u | grep -F '(:0)' | head -n 1 | awk '{print $1}')"

sleep 30
logger "screen.sh slept 30 seconds waiting for other xrandr tasks to finish"

xhost local:root
export XAUTHORITY="/home/$UserName/.Xauthority"

xrandr --output eDP-1-1 --brightness .5

I have tested this on my machine and it works perfectly. You will want to make the following changes:

  • Change /usr/local/bin/ to /avvio/
  • Remove or reduce sleep 30. I need it because I have existing eyesome.sh cron job that sets brightness based on internet daily sunrise and sunset times for my city.
  • Replace the last xrandr line with your three xrandr lines of code

Verify results

There are logger commands in the script. This will let you see it is working by using:

$ journalctl -b -xe | grep screen.sh
Dec 17 14:25:56 alien CRON[1170]: (root) CMD (   /usr/local/bin/screen.sh)
Dec 17 14:25:58 alien root[1728]: screen.sh slept 2 seconds waiting for login
Dec 17 14:26:00 alien root[1790]: screen.sh slept 2 seconds waiting for login
Dec 17 14:26:02 alien root[1973]: screen.sh slept 2 seconds waiting for login
Dec 17 14:26:04 alien root[2070]: screen.sh slept 2 seconds waiting for login
Dec 17 14:26:06 alien root[2300]: screen.sh slept 2 seconds waiting for login
Dec 17 14:26:36 alien root[5355]: screen.sh slept 30 seconds waiting for other xrandr tasks to finish

Original Answer

Cron's @reboot option runs soon after machine is booted and before user is logged in. xrandr commands won't work until user is logged on. You can use this code from eyesome and adapt to your purposes:

export DISPLAY=:0       # For xrandr commands to work.
SpamOn=0                # > 0 = number of times to spam in loop.
SpamCount=5             # How many times we will spam (perform short sleep)
SpamLength=2            # How long spam lasts (how many seconds to sleep)
SpamContext=""          # Why are we spamming? (Login, Suspend or Lid Event)
                        # Future use: "DPMS Change" ie Monitor on or off.
WaitForSignOn () {

    # eyesome daemon is loaded during boot. The user name is required
    # for xrandr external monitor brightness and gamma control. We must
    # wait until user signs on to get .Xauthority file settings.

    SpamOn=10       # Causes 10 iterations of 2 second sleep
    [[ ! -f "$CurrentBrightnessFilename" ]] && rm -f \

    # Wait for user to sign on then get Xserver access for xrandr calls
    while [[ $UserName == "" ]]; do

        sleep "$SpamLength"
        TotalWait=$(( TotalWait + SpamLength ))

        # Find UserName currently logged in.
        UserName="$(who -u | grep -F '(:0)' | head -n 1 | awk '{print $1}')"

    log "Waited $TotalWait seconds for $UserName to login."

    xhost local:root
    export XAUTHORITY="/home/$UserName/.Xauthority"

    if [[ "$fUseDbusMonitor" == true ]] ; then
        echo "$UserName" > "$EyesomeUser"
        sync -d "$EyesomeUser"      # Flush buffer immediately

} # WaitForSignOn
  • Comments are not for extended discussion; this conversation has been moved to chat.
    – Thomas Ward
    Dec 18 '18 at 20:01

For me, I was trying to use redshift which uses randr so I'm thinking this might work:

Your crontab script is missing the environment variable DISPLAY=:0

So just put that at the top of your crontab file.

Also a future debugging technique:

Log the crontab env to a specific file using:

* * * * * env > your_log_file.log

You can then compare that with your current env and see which environment variables you might be missing (for a certain command).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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