Shell – “emacs: standard input is not a tty” when starting Emacs at login

emacsshell

I have Fedora 20 and Gnome3 classic, and I am trying to use the CTRL/ALT/Fn terminal windows. When I want to edit a file with emacs I use the following script so that my Hints file is automatically displayed and emacs is run as a backgound job. This works fine in the non-login terminal from Gnome desktop applications, but in the log-in terminal I get error messages: (obtained by redirection with '&> e' in the CTL/ALT/F2 window)

    home/Harry/bin/emx: line 4: t: Permission denied  
    +---------------------------------------------------+  
    | EmacsHints.txt found and displayed                |  
    | Usage: ./emx <filename> ..                        |  
    |   .. Opens EmacsHints.txt and <filename> in emacs |  
    +---------------------------------------------------+
    emacs: standard input is not a tty

Please can someone explain these, and tell me how to avoid them and use the emx script (no doubt modified) successfully in both log-in and non log-in terminals?

Revised version of my emx script, I have include my notes and debugging stuff:

#!/bin/sh
emxhn="EmacsHints.txt"
emxhf="/home/Harry/emacs/$emxhn"
ps aux | grep $emxhn > t
T=`wc -l t` # no spaces allowed between T and = and value
# echo $T
wc -l t > t1
T=`awk '$1' t1`
# echo $T

echo "+---------------------------------------------------+"

# In the test "" needed round $T else it is split into two commands ..
# .. so are the spaces after [ and before ]
# could be if ( [...] ) then or if [...] ; then 
if [ "$T" = "2 t" ]; then 
#  echo "+----------------------------------------------+"
 echo "| $emxhn already present"\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \  "|"
else
 emacs $emxhf &
 echo "| $emxhn found and displayed"\ \ \ \ \ \ \ \ \ \ \ \ \ \ \  "|"
fi

if [ "$#" = "1" ]; then
 emacs $1 &
else
 echo "| Usage: ./emx <filename> .." \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \  "|"
 echo "|" \   ".. Opens $emxhn and <filename> in emacs" "|"
fi

  echo "+---------------------------------------------------+"

Yes, I see, I have fallen into the X-Y trap, asking X when I should have asked Y, so here's Y

I use emacs a lot but not all the time, and I also have a Hints file, in which I note how to do the tasks I encounter, and I like to have these Hints available while I am using emacs. I tried to automate this so that whenever I start emacs, if the Hints are not already there, then the file is opened as well. That script was my attempt to do so, and has been ok while I have run emacs from a non-login terminal within my Gnome3 classic style GUI. Trying it in a log-in terminal with CTL/ALT/F2 gave the error messages quoted.

I have used and loved Unix and Fedora Linux for many years, but obviously there's still an awful lot more to learn.

Best Answer

Below, I analyse your script. But having done that, I think the answer to the question you should have asked is:

  • Run emacs --daemon from your .profile. This creates a background instance of Emacs.
  • Run emacsclient FILENAME to open a file in Emacs. This creates a new window (either an X11 window, or a window using the current terminal).
  • Load the EmacsHints file in your Emacs startup file: put (find-file "/home/Harry/emacs/EmacsHints.txt") in your .emacs.

We can't tell for sure why you're getting t: Permission denied, since you didn't post the script that generated this error (the script you posted has a comment on line 4). But you're creating a temporary file in the current directory; that's a bad idea in all circumstances, and probably isn't working when you don't have permission to write the current directory.

If you need to create a temporary file, use mktemp. However, here, temporary files are an unnecessary complication: use command substitution to store the output of the commands into a variable.

#!/bin/sh
ps_lines=$(ps aux | grep EmacsHints)
line_count=$(echo "$ps_lines" | wc -l)
T=$(echo "$line_count" | awk '$1')
if [ "$T" = "2" ]; then …

All of this in turn is awfully complicated — just pipe the output of grep into wc, and the awk step isn't doing anything useful.

if [ "$(ps aux | grep EmacsHints | wc -l)" = 2 ]; then …

Furthermore, your test is unreliable: when the EmacsHints file is open, sometimes ps will return one line containing EmacsHints, sometimes two: it depends on the timing of the ps and grep processes. Instead of building your own (which isn't working), use tools dedicated for this purpose: pidof or pgrep.

#!/bin/sh
if pgrep -f 'EmacsHints\.txt' >/dev/null; then …

Voilà! Simpler, and it actually works.

Well, it mostly works. If you open the EmacsHints file in Emacs without specifying it on the command line, this won't be detected. I'd offer a better solution, but I don't understand what you're trying to accomplish. If you always want to have the EmacsHints file open in Emacs, open it from your .emacs.

Emacs is a bit slow to start, but many users (including me) set it up to run when you log in and then never exit it. Run emacs --daemon from your .profile. To open a file in the existing Emacs instance, call emacsclient.

Regarding “standard input is not a tty”, you can run Emacs in the background only if it's opening a GUI window. If you're running Emacs in the terminal, it has to be in the foreground, otherwise it can't access the terminal. If you want to run Emacs in the background only in X:

if [ -n "$DISPLAY" ]; then
  emacs "$1" &
else
  emacs "$1"
fi

By the way, in a shell script, always put double quotes around variable and command substitutions: "$1", "$foo", "$(somecommand)", etc. When the substitution isn't inside double quotes, the value is interpreted not as a string but as a list of glob patterns. This issue typically manifests itself with scripts that fail on file names containing spaces. If you don't understand what all that means, just use double quotes.

Or you could just use emacsclient.

Related Question