Lengthy sleep command not working in script I've written a su.d script to periodically (every 4 hours) back up data from an app using a looped sleep command:

#!/system/bin/sh

(
  # Wait for boot to complete
  until [ "$(getprop sys.boot_completed)" ]
  do
    sleep 300
  done

  while true
  do
    (
      new_dir="/storage/emulated/0/temp/AppData/$(date '+%Y%m%d-%H%M')"
      mkdir -p $new_dir
      cp /data/data/com.example.app/files/*.json $new_dir

      echo "$(date '+%F %T') | app data backup OK!" &gt;&gt; /storage/emulated/0/su.d.log
    ) &amp;

    sleep 14400 # 4 hours
  done
) &amp;


In practice, the script backs up the data only after boot—not every 4 hours.

However, if I enter a remote shell via adb and leave it alone, then the data does get backed up every 4 hours.

How can I force the periodic backup without being permanently connected to a PC? (And why isn't it working as expected?)



EDITS


@Irfan Latif's comment gave me the idea of trying a different interpreter (busybox ash - #!/system/xbin/sh), but the result was the same. I'll try @mirabilos's daemonise suggestion (sh -T- -c '...') next.
Tried @mirabilos's daemonise suggestion with the same result: backs up data only after boot.
Tried nohup:

nohup /system/bin/sh -T- -c '...' &gt;/dev/null 2&gt;&amp;1 &amp;


Same result.
If it’s the terminal thing @IrfanLatif wrote, try this:

#!/system/bin/sh
# run a command block in the background, detached from all terminals
/system/bin/sh -T- -c '
    # Wait for boot to complete
    until [ "$(getprop sys.boot_completed)" ]; do
        sleep 300
    done

    while true; do
        (
            new_dir="/storage/emulated/0/temp/AppData/$(date '\''+%Y%m%d-%H%M'\'')"
            mkdir -p "$new_dir"
            cp /data/data/com.example.app/files/*.json "$new_dir"

            echo "$(date '\''+%F %T'\'') | app data backup OK!" &gt;&gt;/storage/emulated/0/su.d.log
        ) &amp;

        sleep 14400 # 4 hours
    done
'


The -T- option tells the shell to daemon()ise, that is, replace stdin, stdout, stderr with /dev/null and double-fork the command into the background. Perhaps this helps.

I don’t have an off-hand idea why this would otherwise not work. Full disclosure: I’m the mksh developer.