The sole content of debug.sh is
echo "TESTING" >> /tmp/debuglog.txt. Debuglog.txt is not being created.
That's the issue. The kernel will not execute such shell script, because it doesn't start with the mandatory #!/bin/bash telling the kernel to delegate the execution to the bash interpreter.
This very rarely happens because most tools will use a shell to execute a command if it didn't execute immediately. Here's an example when strace-ing perl to execute this command (while searching without success a commandtool that would make execution of the script fail immediately):
$ strace -e execve perl -e 'exec ("/tmp/debug.sh");' execve("/usr/bin/perl", ["perl", "-e", "exec (\"/tmp/debug.sh\");"], [/* 15 vars */]) = 0 execve("/tmp/debug.sh", ["/tmp/debug.sh"], [/* 15 vars */]) = -1 ENOEXEC (Exec format error) execve("/bin/sh", ["/bin/sh", "/tmp/debug.sh"], [/* 15 vars */]) = 0 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=14452, si_uid=1000, si_status=0, si_utime=0, si_stime=0} --- +++ exited with 0 +++ It attempted first to execute the script without interpreter in its first line and got:
ENOEXEC (Exec format error) and then tried again by inserting a shell before so it works. Here /bin/sh, is not even bash in this environment, so if the script includes bash constructs, it would subtly misbehave later.
Had /tmp/debug.sh be this (and with the u+rx perms):
#!/bin/bash echo "TESTING" >> /tmp/debuglog.txt then:
$ strace -e execve perl -e 'exec ("/tmp/debug.sh");' execve("/usr/bin/perl", ["perl", "-e", "exec (\"/tmp/debug.sh\");"], [/* 15 vars */]) = 0 execve("/tmp/debug.sh", ["/tmp/debug.sh"], [/* 15 vars */]) = 0 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=14474, si_uid=1000, si_status=0, si_utime=0, si_stime=0} --- +++ exited with 0 +++ Then /tmp/debug.sh would have be executed directly by the kernel (which would have actually defered the execution to /bin/bash).
udev doesn't attempt to do this, so it requires a valid binary for the kernel as first file in the command. Either supplying it directly, either by supplying a script which is an adequate executable from the point of view of the kernel by starting with the #!/path/to/interpreter line.