How can I tell whether I'm in a screen? - linux

When using screen in linux, how can I tell if I'm in a screen or not?
I could do exit and I'll exit a screen if I was in one, but if I wasn't, then I'll end up closing my terminal.
When doing screen -r, I could see if I have other screens attached, but how do I know if my current terminal is one of those attached screens?

Check $STY. If it's null, you're on a "real" terminal. If it contains anything, it's the name of the screen you're in.
If you are not in screen:
eric#dev ~ $ echo $STY
eric#dev ~ $
If you are in screen:
eric#dev ~ $ echo $STY
2026.pts-0.ip-10-0-1-71

Another way I've done it is to echo $TERM.
$ echo $TERM
screen
Since I end up doing this a lot, I added an alias into my .bashrc file:
alias trm='echo $TERM'
This way, whether in screen or not, if I just execute 'trm' it will show me whether I'm in SCREEN or elsewhere (usually XTERM).

Alternative approach to check if you are in screen.
type:
Ctrl-a ?
If you see the screen help you are in screen.
Otherwise you'll get a question mark '?' on the prompt.

Since all of the other methods here rely on environment variables (which can simply be overridden) or the command character for screen (which can also be overridden), the most foolproof way to check would be to list all the ancestors of the current process.
pstree --show-parents -p $$ | head -n 1 | sed 's/\(.*\)+.*/\1/' | grep screen | wc -l
If it prints 1, then the current process you're running has an ancestor with the word 'screen' in the executable's name, otherwise there wasn't.
A more facile visible inspection might be obtained from:
pstree --show-parents -p $$ | head -n 1 | sed 's/\(.*\)+.*/\1/' | less

My solution to the problem is a lot simpler: just hitting TAB makes the full terminal blink (a quick video inversion) if you are inside GNU Screen.
Tested working on most Linux (Ubuntu, Kali, Debian, RaspBerry... etc) and FreeBSD, GUI and any terminal, local or remote, including CtrlAltFn ones.
As an exception for this method, please, note this (rather complex, but possible) case scenario:
1.- SSH into computer A (lets assume Linux).
2.- Enter a new screen -S AScr from remote terminal on computer A.
3.- SSH from GNU Screen AScr terminal into Computer B.
4.- Enter a new screen -S BScr from remote terminal on computer B.
You are inside a Screen on cases 2 and 4, and outside a Screen on cases 1 and 3, but the terminal will blink on cases 2, 3 and 4.

While ssh'd into a remote (older) system I noticed that $TERM indicated I was using 'screen-256color', however there was no termcap/terminfo entry for that, so I was forced to resort to the following in .bashrc to prevent the terminal from producing occasional garbage:
case $TERM in
(screen-256color) export TERM='screen'
esac
to get it to use the plain entry instead.
TL;DR, $TERM will usually indicate if you are in a screen session when ssh'd remotely. You can use case $TERM in (screen*) echo "you are in a screen session"; esac if you just want a visual clue and don't need to do something specific

Add one or more of the followings into your .bashrc
alias mysession='echo ${STY}'
alias myterm='echo ${TERM}'
alias isscreen='if test -n "$STY"; then echo " screen session: ${STY}"; else echo " NOT a screen session"; fi'
Then you can know if you are inside a screen by typing simple commands.

The problem with most of the above answers is that we might be in a subshell of an attached screen session. Or we might be opening a shell to a remote host from within a screen session. In the former case, we can walk the process tree parentage and match for the screen program name. In the latter case, most of the time, we can check the TERM variable for something like screen*.
My answer os similar to /u/Parthian-Shot but not so dependent on the pstree utility; the options he use are not available to me. On the other hand, my implementation is still Linux-dependent: for non-Linux systems, one must tweak the ps command; for systems with older shells that don't support arrays, you'll have yet more work-arounds. But anyway:
ps_walk_parents() {
local tmp
local ppid=$PPID
while [[ $ppid != 1 ]]; do
tmp=($( ps -o ppid,comm -p $ppid ))
ppid=${tmp[0]} # grab parent pid
echo ${tmp[1]} # output corresponding command name
done
}
if [[ "$TERM" =~ screen* ]] || ps_walk_parents |grep -qxi screen ; then
# we are in a screen terminal
fi
We could optimize our function a bit to stop searching if/when a process parent matches the target command name ("screen"), but in general, the function will only hit 2 to 3 iterations. Presumably you want to put this code in some startup initialization such as .bashrc or .profile or something, so again, not worth optimizing.

screen -ls can tell you.
Outside screen:
$ screen -ls
There are screens on:
16954.pts-1.auds916 (Detached)
242.pts-8.auds916 (Detached)
2 Sockets in /tmp/screens/S-glennj.
Inside a screen:
$ screen -ls
There are screens on:
16954.pts-1.auds916 (Attached)
242.pts-8.auds916 (Detached)
2 Sockets in /tmp/screens/S-glennj.

Related

Why when I cat the node directory in `/usr/local/bin` does it unleash cthulhu?

So I was installing node and somehow I ended up in the /user/local/bin folder checking what was there.
I wanted to so a ls | grep node but did a ls | cat node. The node directory then started to show itself in all its glory. I chuckled, laughed, then stopped the cat but that left my terminal looking something like this:
It is easily fixable by exiting the window.
I don't recommend you try it but i've managed to recreate it reliably. Just cat the node directory leave it for a few seconds then cancel it.
My question is what on earth is going on here? AFAIK using cat shouldn't be able to make this stuff happen.
Terminals interpret certain combinations of bytes as commands. This is how command line programs can output colors, or change the cursor position. What you're seeing is the output after one of these commands activated a box drawing character set by accident. You can activate it yourself with echo or printf:
my cool prompt$ printf '\033(0'
└≤ ␌⎺⎺┌ ⎻⎼⎺└⎻├$
To get out of this mess, type reset and press Enter - it will clear the screen and set all settings back to default.
└≤ ␌⎺⎺┌ ⎻⎼⎺└⎻├$ ⎼␊⎽␊├
(..screen clears..)
my cool prompt$
You managed to output the contents of the node executable to the terminal. What happens when you output random octets to the terminal depends on what those characters are and on the terminal. It often leaves the terminal in a state that the user did not really expect.

using screen session in shebang of a bash script

I have recently come across this post which says that it is possible to force a script to run in screen with a shebang. My question is, how does one do this if I want to reconnect to an existing screen session (and thus force the script to run under screen).
So, on my server, when I do screen -list, I see:
There is a screen on:
22566.myscreen (10/26/13 23:47:09) (Detached)
1 Socket in /var/run/screen/S-admin.
Now, I have the following bash script, and I would like the bash script to be run with the above screen session. At the moment, I have something like this:
#!/usr/bin/screen -r "myscreen" /bin/bash
# /home/foo/jobscripts/script.sh
#
echo $STY
git status
touch /home/foo/jobscripts/testsuccess.txt
exit 0
... but this obviously does not work and tells me Error: Unknown option r "myscreen" /bin/bash Wondering if there was a way to specify in shebang to reattach to my above screen.
For Linux, I think we should just use something like pid.sessionname.
For other Unix-like OS, it may also indicate the TTY like this pid.tty.sessionname.
To be sure, consult your manpage of screen : man screen

can one gnu screen session have both split and non split workspaces?

When using GNU screen, if you enter a screen session and then split it into desired layout.. is it possible to also have a full screen shell that you can switch to within the same session? Or once you start splitting does that mean you are constrained to one view and you can only alternate between visible split panes and then switch active shells within those panes?
I often split a screen session to monitor multiple logs or looped command output at the same time but I'd also like a full screen shell to work on as well without having to have a separate screen sessions that i need to detach from split/attach to full screen etc..
If screen can't do this, can tmux or similar do it? Any pointers?
many thanks
fLo
I tried to do this with screen. The best I could come up with was to have multiple sessions (with different escape characters). The multiple log windows were all in one session, and the other session contains, in one window, screen -r log. Then I could split the log session, and still be able to cycle through the other session windows.
I believe it is possible in tmux, but I have not made the switch (yet).
EDIT: It definitely is possible, and very easy, in tmux. And the switch was very easy (there's a screen-keys.conf file in tmux examples that I started with). This is a script I wrote to create a full screen session with 3 windows, the third has 3 panes in it, one 20% and the other two 40%. It's callable from crontab: #reboot
tmux new-session -d -s base /bin/bash
tmuxwin() {
tmux new-window -t base -n $1 /bin/bash
sleep 1
shift
tmux send "$1" C-m
}
tmuxwin second "echo second"
# These all end up in one window
tmuxwin thirddotone "echo 3.1"
tmuxwin thirddottwo "echo 3.2"
tmuxwin thirddotthree "echo 3.3"
# join 3.1 to 3.2. Give 3.1 20%
tmux select-window thirddotone
tmux joinp -p 80 -s +
# join 3.3 to 3.2. Even split
tmux joinp -s +
# and fix the names...
tmux rename-window three
# I am waiting for you, Vizzini. You told me to go back to the beginning.
# So I have. This is where I am, and this is where I’ll stay. I will not be moved.
tmux select-window -t 0
So my recommendation is to switch to tmux. I've been using tmux for less than a week and am not looking back.

Bash: call script with customized keyboard shortcuts?

Lets say I have a script, "myscript.sh", with contents being simply echo $PWD. I'd like to bind somehow this script to a key combo in bash (gnome-terminal) - so that when I press this key combination, the output of "myscript.sh" is inserted ("pasted") at the cursor position in the terminal.
Apparently, bash history and line manipulation is handled by readline - and the references I got for bash keyboard shortcuts, do reference readline:
bash keyboard shortcuts
Bash Reference Manual: Bindable Readline Commands
I've also seen in Bash Reference Manual: Readline Init File Syntax that the key bindings for bash can be listed by using bind -p (see help bind [not 'man bind'] for more). So maybe this question would better be titled as "_binding macros to custom keyboard shortcuts in readline" :) But in any case, is what I want possible to do?
I guess an alternative would be to have the script be something like "pwd | xsel -b", and then I call it on terminal - and I can paste afterwards; but I'd still like a single keyboard shortcut instead, say like Ctrl-Alt-H (which seems to be not used for anything), which will immediately insert/paste script output when pressed.
Thanks in advance,
Cheers!
EDIT: Just to clarify - here is my use case where I'd like this facility. I'm usually cd'd in a project folder, usually named something like myproject-folder-0012a, which is under revision control by svn. And there is a bunch of these folders. So quite often, I do commits where the first word of the message is the directory name, as in:
svn ci -m "myproject-folder-0012a: here a commit message"
But that is what I don't like - first I type 11 characters, which go rather fast:
svn ci -m "
And then, I cannot use autocompletion to get the name (i'm inside the folder) - which means I either have to fully type it (no way :)), or I copy paste it from the prompt (which requires selection - press mouse, drag, release mouse; then Ctrl+Shift+C, and then Ctrl+Shift+V, plus any left/right keys if I miss allignment - plus deletions and such if I make the copy wrong).
Meaning - so much work, just to get the bloody folder name for a bloody commit message :( I'd MUCH rather press something like (say) Ctrl-Alt-H, and have the folder name automatically inserted at cursor position, and be done with it :)
My suggestion for xsel is only because I could put it into a "global" script - say symlink it as /usr/bin/myscript (and obviously, the contents of the script are echo $(basename $PWD) rather than just pwd for my needs), and then I could do:
$ myscript # this puts directory name in clipboard
$ svn ci -m "[CTRL+SHIFT+V TO PASTE HERE]myproject-folder-0012a[NOW TYPE]: here a commit message"
... which sort of makes the workload less, but still - then I have to remember what the script name is, and call it, before I type the svn command (and I don't always remember that)... And still - I have to call a command, and then press a key combo; why shouldn't I just press a key combo once, and be done with it ??! :)
Well, hope this clarifies my problem a bit better ....
EDIT2: However, another reason why a bash keyboard shortcut would be useful, is that then I could also "paste/insert current directory name" not only in shell commands - but also in terminal programs, say like nano (where it would, arguably, be more difficult to use bash script or function expansion directly).
Simple version:
This command at a shell prompt:
bind '"\ee": "${PWD##*/}\e\C-e"'
or this line added to your ~/.inputrc:
"\ee": "${PWD##*/}\e\C-e"
will cause Alt-e to insert the basename of the current directory on the command line. It requires that the default binding of the readline function shell-expand-line which is \e\C-e be present (this could be adapted if it's different). I'm also making the assumption that you're using Bash's emacs mode.
Unfortunately, it causes things that have already been typed to be expanded as well. One of the affects of this is that after having typed:
svn ci -m "
and pressing Alt-e, the quotation mark will have disappeared. There are a couple of ways to deal with this.
One, assume that all you'll lose is the quote and either manually add it back or have the readline macro add it for you:
bind '"\ee": "${PWD##*/}\e\C-e\eb\"\C-e"'
which just isn't very satisfactory.
Advanced version:
Or, two, kill the line, do the insertion, then yank the line back:
bind '"\ee": " \C-u \C-a\C-k${PWD##*/}\e\C-e\C-y\C-a\C-y\ey\b"'
or
bind '"\ee": " \C-u \C-a\C-k${PWD##*/}\e\C-e\C-y\C-a\C-y\ey\b\ef\C-f"'
This leaves the rest of the line intact (nothing else is expanded or deleted), but it uses the kill ring, so it may leave it in a state that's different than you expect (if you're using it). It also inserts a space after the inserted directory name (the spaces in the macro are used to ensure that older kill-ring contents are not regurgitated if the macro is executed at the beginning or end of the line). The macro should work regardless of the position of the cursor in the line. The insertion will be made at the cursor's position, leaving the cursor in the same position [in the first version].
Edit: The second version leaves the cursor after the dirname and space that are inserted.
Edit 2:
The readline function shell-forward-word (unbound) does a better job than forward-word (\ef) for this. You can make use of that like this:
bind '"\ew":shell-forward-word'
bind '"\ee": " \C-u \C-a\C-k${PWD##*/}\e\C-e\C-y\C-a\C-y\ey\b\ew\C-f"'
By the way, you should know that Bash keyboard shortcuts are not active in other programs such as nano.
Ok, not really an answer, but I'd just like to summarize the comments I got so far, which are useful for my problem. However, the question as it stands - in respect to bash keyboard shortcuts running arbitrary scripts - is still not answered (I'd still prefer doing all this with a single key combo :))
First, I can use a 'global' script like:
$ sudo bash -c 'cat > /usr/bin/bpwd <<EOF
#!/bin/bash
basepwd=\$(basename \$(pwd))
echo -n \$basepwd # suppress line ending
# exec 1>/dev/null # debug: redir stdout to null
echo -n \$basepwd | xsel -i -b # suppress LF, and make xsel read from stdin
# exec 1>/dev/tty # debug: restore stdout
EOF
chmod +x /usr/bin/bpwd'
Or, I can add bash functions to my .bashrc (note: make sure you reload bash after you add these lines to .bashrc - for example, simply by typing bash in your current terminal):
$ echo '
bpwd2() { basepwd=${PWD##*/} ; echo -n $basepwd | xsel -i -b ; echo -n $basepwd ; }
svnci-test() { echo -n "$(bpwd2): $*" ; }
svnci-m() { svn ci -m "$(bpwd2): $*" ; }' >> ~/.bashrc
Basically, I misunderstood Reese Moore's suggestion originally - you can indeed use backticks - consider this command session (after the above commands have been ran):
$ bpwd
Desktop\
$ bpwd2
Desktop\
$ echo `bpwd`
Desktop
$ echo "`bpwd2` 2"
Desktop 2
This is what I needed to understand Moore's "the output from the backticked commands will be used as input on the executed command" (however, one also needs to take care to clean the line endings from the output); or, in my case, I can call
svn ci -m "`bpwd`: my message here"
# svn ci -m "${PWD##*/}: my message here" # alternatively
... or, I could follow camh's suggestion, and use svnci-m as a function (in my case, I almost never use additional arguments to svn ci, and so my version is slightly different). And to test whether arguments are passed correctly, I can use the svnci-test function:
$ svnci-test "my message"
Desktop: my message\
Thanks for the comments so far,
Cheers!
One way to do what you want with a single key press is to take advantage of programmable completion in bash. You possibly have some programmable completion set up with the bash_completion tool/package. If not, look into that to see the specifics of how it is done.
The idea is to have the programmable completion recognise when you have hit at the start of a svn commit message and then have it return a single completion which is the text you want to insert (the basename of the current directory).
I've only dabbled with programmable completion so I can't give you the details, but the above-mentioned bash_completion package or the subversion completion script may be a good start.

How do I launch an editor from a shell script?

I would like my tcsh script to launch an editor (e.g., vi, emacs):
#!/bin/tcsh
vi my_file
This starts up vi with my_file but first displays a warning "Vim: Warning: Output is not to a terminal" and my keystrokes don't appear on the screen. After I kill vi, my terminal window is messed up (no newlines), requiring a "reset". I tried "emacs -nw", "xemacs -nw", and pico with similar results. "xemacs" works but launches a separate window. I want to reuse the same terminal window.
Is there a way to launch an editor from a script so that it reuses the same terminal window?
I answered my own question! You have to redirect terminal input and output:
#!/bin/tcsh
vi my_file < `tty` > `tty`
The reason you're getting the error is that when you start a shell in your environment, it's starting in a subshell that has STDIN and STDOUT not connected to a TTY — probably because this is in something like a pipeline. When you redirect, you're opening a new connection directly to the device. So, for example, your command line turns
$ vi < `tty` > `tty`
into
$ vi < /dev/ttys000 > /dev/ttys000
So you're not really using your old STDIN/STDOUT, you're creating two new files and mapping them to your vi process's STDIN/STDOUT.
Now, tell us what you're doing with this and we'll tell you how to avoid this kludge.
I wanted to do something similar. I wanted an alias that would find the last file I was working on, and open it in vi(1) for editing. Anyway, I couldn't figure out how to do it as a readable alias (in tcsh) so I just created an ugly shell script (csh because I'm old) instead:
#!/bin/csh
set DIR = "~/www/TooMuchRock/shows/"
set file = $DIR`ls -t $DIR | head -1`
set tty = `tty`
vi $file <$tty >$tty
(1) kraftwerk:bin> which vi
vi: aliased to /usr/local/bin/vim -u ~/.exrc
Absolutely. :-)
Write your script and have it call the EDITOR environment variable, which you will have set to "emacsclient". Then start up Emacs, execute M-x server-start, switch to a shell buffer (M-x shell) and execute your script. Emacsclient will pop up the thing to be edited and C-x # will act as a "done" command and take you back to your script with edits completed or aborted, as you choose.
Enjoy.
Edit: I meant to add that these days Emacs IS my terminal program. I have dozens of shell buffers and never have to worry about losing output and can use all the power of Emacs to manipulate and analyse the terminal output. And have Emacs scripts generate input to the shells. Awesome actually. For example, watching Tomcat output scroll by in a shell buffer while editing sources or processing mail or doing most any Emacs thing is very convenient. When a Tomcat stack trace appears I can quickly respond to it.
Had the same trouble with 'pinfo' in a shell script 'while' loop. The line can be used in the script, it uses 'ps' to find the tty of the current process number, "$$", and stores that tty in $KEY_TTY:
KEY_TTY=/dev/`ps | grep $$ | tr -s '[:blank:]' | cut -d " " -f 3`
Later in the script, just call the tty-only proggie, with $KEY_TTY as input, in my case it was:
pinfo -m $s $page < $KEY_TTY
For 'vi' it'd be:
vi $a < $KEY_TTY > $KEY_TTY
The advantage is that the script as a whole can still accept STDIN input, and 'vi' (or whatever) should work fine -- without having to remember to set any environmental variables before running the script.
Set your terminal tty to a variable, and then redirect the editor i/o through that variable.
In your script:
#!/bin/sh
ls | while read a; do vi $a < $MYTTY >$MYTTY; done
And then execute the script with:
$ MYTTY=`tty` ./myscript >/tmp/log
I was able to get the desired behavior under bash+Cygwin+Terminator:
#!/bin/bash
vim foo
Run the script, vim loads, no error messages, behaves as normal. There are undoubtedly dozens of variations between our setups, however, so I can't hazard a guess as to what makes the difference. I'm curious what it is, but you got it working, which is the important part.

Resources