2

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

#!/bin/bash
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
Kulfy
  • 17,696
Fab1can
  • 107

2 Answers2

1

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:

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
@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.

#!/bin/bash

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

wait until user signs on to get .Xauthority file settings.

UserName="" 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}')" done

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
    SpamContext="Login"
    TotalWait=0
    [[ ! -f "$CurrentBrightnessFilename" ]] && rm -f \
            "$CurrentBrightnessFilename"

    # Wait for user to sign on then get Xserver access for xrandr calls
    UserName=""
    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}')"
    done

    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
    fi

} # WaitForSignOn
0

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