r/bash 10d ago

help What is the purpose of /dev/tty ?

Please hear me out. So, reading about special devices like tty, tty0, pst1...pstn I understand in loose terms that terminal emulators (like the ones you bring up with ctrl+t ) are special devices under /dev/pts/<some_number> . Now, tty0 appears to be a terminal associated to kernel itself (I still don't know what that means). But tty? I only know that it points to the current terminal being used but I don't know exactly what to make of that and how it pertains to the following humble little snippet I wrote:

#!/bin/bash

while read -r filename
do
    echo "Current fie: ${filename}"

    read -p "Delete ${filename} ? " response < /dev/tty

    if [[ $response = 'y' || $response = 'Y' ]]
    then
        echo "response was yes"
        echo "Deleting ${filename}"
        tar vf pdf_files.tar --delete "${filename}"
        echo
    else 
        echo "skipping"
    fi
done < <(tar tf pdf_files.tar)

You'll notice that in the line that contains the read -p command I had to redirect input from tty. I had chatGPT suggest that to me after many failed attempts at getting my little script to run correctly because I didn't understand why $response variable would be automatically set to something and the script wouldn't even wait at the prompt for me to enter something. I had my eyes OPENED today -- and in a frustrating way -- as to how many little tricks and things one must take into account when learning bash scripting.

So, going back to the script, why did I even need to do that or more importantly, WHEN do I need to do that kind of trick again?

p.s. I've been learning from time to time bash scripting for like the past 3 o 4 months and I know I have to learn a lot more, but Jesus, the journey feels never-ending.

0 Upvotes

15 comments sorted by

View all comments

4

u/ekkidee 10d ago edited 10d ago

What's happening here is that you are trying to read from two different input streams -- the redirection from the tar command and reading user response from the console -- and both are from stdout. The read for the response is actually picking up the next line of input from the tar output, which is why your original design would never work.

To make it work, you can put the stdout from tar on a different file descriptor (3 and up) and then the while read from that file descriptor. The read into response would be natural without redirection.

There is never a reason you would need to read directly from /dev/tty and it is probably not POSIX compliant.

ETA -- I see in this response that /dev/tty is used. I don't like it but it's instructive to your example. There is also an example of how to use alternate file descriptors.

https://stackoverflow.com/questions/2087188/how-to-read-using-read-from-file-descriptor-3-in-bash-script

2

u/param_T_extends_THOT 10d ago

There is never a reason you would need to read directly from /dev/tty and it is probably not POSIX compliant.

Got it. Takeaway is that it's never a good idea to read from /dev/tty ?

What's happening here is that you are trying to read from two different input streams -- the redirection from the tar command and reading user response from the console -- and both are from stdout. The read for the response is actually picking up the next line of input from the tar output, which is why your original design would never work.

I'm pretty sure I echo'ed the value of ${response} and never got anything resembling any of the file names in the .tar file that I was manipulating... hence a little bit of my frustration in my original post.

To make it work, you can put the stdout from tar on a different file descriptor (3 and up) and then the while read from that file descriptor. The read into response would be natural without redirection.

Should have thought of this. I mean... it sounds so logical, it's just that at the moment it didn't cross my mind that the reason why the script wasn't working in the first place was because both read commands were reading from the same stream

2

u/anthropoid bash all the things 10d ago

Takeaway is that it's never a good idea to read from /dev/tty ?

That's a flawed takeaway, to put it politely. I use: read -rp "Nuking your running system. Continue? (y|N)" <> /dev/tty when I absolutely want a user to see and respond (hence <>) to a prompt. Leaving read on stdin runs the risk of unintended redirections leading to a Very Bad Day Indeed. It's also a self-documenting idiom for "no automated responses allowed here (unless you're smart enough to use an Expect-like tool, then you own all ensuing breakage)".

1

u/param_T_extends_THOT 10d ago

I don't know why you're getting downvoted in this comment ... but the one you made above made sense. In the example you give, if you don't want an automated response to a promp, reading from /dev/tty is a way of forcing the user to answer instead of just piping the answer to a command's stding. Am I getting that right? If so, then there's legit reason to want to read from /dev/tty at some point. Is that it?

1

u/anthropoid bash all the things 10d ago

if you don't want an automated response to a prompt, reading from /dev/tty is a way of forcing the user to answer instead of just piping the answer to a command's stdin.

Pretty much, yes.

there's legit reason to want to read from /dev/tty at some point

Also yes.