1

I'm writing a custom gnome-terminal profile which I want to stop with any key I choose. After pressing the key, my intention is to complete all my commands at that moment and start su. I've tried adding a & to my command,but it didn't work. I'm attaching some info:

MY CODE:

su --command 'read -n 1 -s key; if [ "$key" == "g" ]; then su; fi;'
echo -n "W" 
sleep 0.09
echo -n "e" 
sleep 0.09
echo -n "l"
sleep 0.09
echo -n "c"
sleep 0.09
echo -n "o"
sleep 0.09 
echo -n "m"
sleep 0.09 
echo -n "e"  
sleep 0.09 

EXPECTED RESULT:

[characters being echoed properly until...]

[key pressed]

Welcome

root@myuser:~#
  • In your script, the su is sort of redundant. Just drop to shell with /bin/sh -l or similar. – Otheus Feb 6 '16 at 17:55
  • Allright, I updated my answer, it is as close to complete as I could get with only bash, but it does what you asked. – Cestarian Feb 6 '16 at 19:01
  • Oh nevermind, with a bit more work I managed to get it exactly the way you wanted. – Cestarian Feb 6 '16 at 19:14
  • @Otheus I use su -c because my intention is to create a modified gnome-terminal profile that displays a message every time somebody uses it. – xvlaze Feb 6 '16 at 23:54
  • I don't get it. But why do another su? Dont you just want to drop into the shell? – Otheus Feb 6 '16 at 23:58
0

This doesn't work on a lot of levels. Chiefly, bash isn't really good for multi-threaded programming. But if you're going to do it this way, you have to realize two things: (1) in order for your key-read "thread" to work, it has to have exclusive access to the tty. (2) When you put a process in the background, it will naturally copy stdin from the current process' tty. (3) Usually the shell will detect this and stop the background process.

Only foreground processes are allowed to read from or, if the user so specifies with stty tostop, write to the terminal. Background processes which attempt to read from (write to when stty tostop is in effect) the terminal are sent a SIGTTIN (SIGTTOU) signal by the kernel's terminal driver, which, unless caught, suspends the process.

You can see that here:

otheus@otheus-VirtualBox ~ $ ( while true; read x; do echo $x; done; ) &
[1] 2841
otheus@otheus-VirtualBox ~ $ 

[1]+  Stopped                 ( while true; read x; do
    echo $x;
done )

So the tty-reading process should be in the foreground. The background can do the "work", but make sure you close stdin first: <&-

To stop the "worker" process, you will have to know its pid. To do that, you need to enable job-control within a script (it's off by default). set -m does this. Start it and kill %- after the keypress. You may want to make sure the keypress loop ends when the worker does. You do your key-monitor thread:

start_worker &

while jobs %- &>/dev/null; do 
   read -n 1 -s -t 1 key
   # test key
   if [[ $key == q ]]; then
      kill -1 %-
      break
   fi
fi
wait

The while condition tests if the job is still running/recognized. Once it ends, jobs will return false, and the loop exits. The read command now additionally times out after 1 second. Finally, after the loop exits, do a wait to make sure the job is "cleaned up". (If you have other jobs running, that will hang here.)

The other thing is: what you're trying to accomplish is inherently dangerous. Mixing root access and bash scripting is dangerous. There are some topics to address here, such as what happens when the user hits Control-C or Ctl-Z.

Lastly, I'm not even sure you can mix the worker thread with su as in your example. When su runs, it will change the current tty to root, preventing your worker thread from outputting to it.

  • I can't implement this to my code as I'm trying to create a custom terminal profile, and I have to write some commands after a su -c. I'm also forced to use root because I'm working from a Live USB unit. – xvlaze Feb 6 '16 at 23:57
  • @xvlaze I don't get it. What's a custom terminal profile? Why root? Don't most live usbs have a generic non root login? – Otheus Feb 7 '16 at 22:31
  • I think this will explain itself better than I do: help.gnome.org/users/gnome-terminal/stable/… I'm using Kali Linux Live, which forces me to use root user every time. I've never had the possibility to run it as a standard user, don't ask me why. Anyway, I'm OK with it, as I have got used to it. – xvlaze Feb 7 '16 at 22:33
  • So you want to be able to interrupt the custom profile setup? – Otheus Feb 7 '16 at 22:39
  • I want to interrupt my own custom command list (the echoes), yes. Whenever I press a key, I want the message to be displayed completely and invoke su – xvlaze Feb 7 '16 at 22:45
0

The closest I could ever get with a similar issue was something like this...

First create a script named inputproc:

read -n1

Then create a script called mainscript:

array=(W e l c o m e)
buf=0
while pgrep "inputproc" > /dev/null; do
    echo -n ${array[buf]}
    ((buf++))
    sleep 0.09
done
#Insert any commands you want to run afterwards here...

Then execute them with this command

./mainscript & ./inputproc

And well, this does exactly what you wanted. I couldn't find a way of doing it with just one script, but amazingly enough, I found a way to do it with just one terminal window.

Besides the obvious (using a while loop to check if inputproc is running before each echo command, and using an array to echo the desired letters in order) this works by running mainscript in the background while running inputproc in the foreground. It is not without flaws, but it's the closest you can get to your desired result I believe.

  • That's not what I'm looking for, as I don't want any prompt to appear in my screen. I just want to press a key in order to display the whole message. – xvlaze Feb 6 '16 at 17:20
  • @xvlaze Oh I see, that's quite troublesome, I recall doing something similar in the past though, let me look it up. – Cestarian Feb 6 '16 at 17:22
  • @xvlaze Found a way to do it, surprisingly enough. – Cestarian Feb 6 '16 at 19:21
  • couldn't you put mainscript into a function and have that function invoked within inputproc with job control? – Otheus Feb 6 '16 at 19:29
  • @Otheus I don't know, never tried anything like that. – Cestarian Feb 6 '16 at 20:49

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.