how can I list terminals currently in use - bash

I want to set the terminal my script is running in as a variable in a bash shell script.
as in tty7, or pts/0 or ttyacm0 etc...
I tried printenv , sudo printenv and declare -xp
but in the list I only saw ssh_term. But I know I have a script running in /dev/tty6
so it isnt listing all the terminals in use, just the current terminal.
is there a simple way to list all the shells in use?
UPDATE:
who -a seems like all the terminals used in the uptime durration.
the ones that say old are the ones where I know there are other scripts running.
But what is this +/- business?
j0h - tty6 2014-05-16 07:50 old 9593
LOGIN tty1 2014-05-15 19:10 1675 id=1
j0h + tty7 2014-05-15 19:13 old 1936

If I have understood the problem correctly you are looking for terminals used by a particular script, if so you can use something like:
x=($(ps aux | grep script_name)| awk '{print $7}') #you may have to check which column to filter
all terminals used by script would be in array x then you can
for i in ${x[*]}
do
echo $i
done
for getting individual values

To obtain the current shell that you are using, there is the command
tty
that print the file name of the terminal connected to standard input e.g. /dev/pts/51
To see all the shell you can use w or who.
who -a and who -p should give you some information more...
Read the man to have a quick view on the possibilities. (You can select the user...)
Update:
Let we say your script is called MyScript.sh. If you add as a 1st line
#!/bin/bash
you change the attribute
chmod u+x MyScript.sh
and you execute it with ./MyScript.sh later you can search directly them with
pgrep -wal MyScript.sh
(It will return the pid of the processes)

Related

How to record shell interaction from a background script

I want to write a background sh (it can be python or any other language actually) script very much like script.
Its main purpose is to run on the background after invoked and listen to inputs (not the outputs nor the PS1 shell prompt string nor keystrokes like "End", "Ctrl", arrow-keys, etc.) that the user enters to the shell from which the script was originally invoked and then record them.
The dumbest approach would use script and then try to subtract PS1 and outputs from the generated file. But this would be error-prone and there sure are better ways to do this.
I've read about pam_tty_audit but I'm not sure if one can easily filter out just the user input and I'm afraid it won't work for all Linux distributions.
What else can I look into to accomplish that?
A quick example illustrating what I seek:
The user would input this to the shell:
$ ./myscript
MyScript started in the background
$ echo "foo"
$ sudo apt install netcat
[sudo] password for user: MYPASSWORD
...
Do you want to continue? [Y/n] NO
...
$ exit
MyScript exited
And my script would render this output file:
#!/bin/bash
eval "echo \"foo\""
echo "NO" | echo "MYPASSWORD" | eval "sudo apt install netcat"
Obs.: Capturing the password typed for sudo is not really something I would like to perform, the above example is just the first which came to mind.

Is there a way to redirect all stdout and stderr to systemd journal from within script?

I like the idea of using systemd's journal to view and manage the logs of my own scripts. I have become aware you can log to journal from my user scripts on a per message basis..
echo 'hello' | systemd-cat -t myscript -p emerg
Is there a way to redirect all messages to journald, even those generated by other commands? Like..
exec &> systemd-cat
Update:
Some partial success.
Tried Inian's suggestion from terminal.
~/scripts/myscript.sh 2>&1 | systemd-cat -t myscript.sh
and it worked, stdout and stderr were directed to systemd's journal.
Curiously,
~/scripts/myscript.sh &> | systemd-cat -t myscript.sh
didn't work in my Bash terminal.
I still need to find a way to do this inside my script for when other programs call my script.
I tried..
exec 2>&1 | systemd-cat -t myscript.sh
but it doesn't work.
Update 2:
From terminal
systemd-cat ~/scripts/myscript.sh
works. But I'm still looking for a way to do this from within the script.
A pipe to systemd-cat is a process which needs to run concurrently with your script. Bash offers a facility for this, though it's not portable to POSIX sh.
exec > >(systemd-cat -t myscript -p emerg) 2>&1
The >(command) process substitution starts another process and returns a pseudo-filename (something like /dev/fd/63) which you can redirect into. This is basically a wrapper for the mkfifo hacks you could do if you wanted to port this to POSIX sh.
If your script happens to not be a shell script, but some other programming language that allows loading extension modules linked to -lsystemd, there is another way. There is a library function sd_journal_stream_fd that quite precisely matches the task at hand. Calling it from bash itself (as opposed to some child) seems difficult at best. In Python for instance, it is available as systemd.journal.stream. What this function does in essence is connecting a unix domain stream socket and communicating what kind of data is being transmitted (e.g. priority). The difficult part with a shell here is making it connect a unix domain socket (as opposed to connecting in a child).
The key idea to this answer was given by Freenode/libera.chat user grawity.
Apparently, and for reasons that are beyond me, you can't really redirect all stdout and stderr to journald from within a script because it has to be piped in. To work around that I found a trick people were using with syslog's logger which works similarly.
You can wrap all your code into a function and then pipe the function into systemd-cat.
#!/bin/bash
mycode(){
echo "hello world"
echor "echo typo producing error"
}
mycode | systemd-cat -t myscript.sh
exit 0
And then to search journal logs..
journalctl -t myscript.sh --since yesterday
I'm disappointed there isn't a more direct way of doing this.

Effective Methods of changing Shells in UNIX

I used to work with UNIX a couple years ago, and I am just starting to get back into it again. I was wondering if anyone could help me with a question.
For example, if I am in bash, I say chsh --shell /bin/tcsh after this I am prompted to enter my password. If I try to say echo $SHELL it will not tell me I have changed shells. It still tells me I am in bash, not C shell. So I have to exit and restart. Once I log back it, then it tells I am in C shell.
Is there a more effective method to change shells? One that does not require me having to log in and out?
Thank you in advance.
chsh(1): change your login shell
Once you change your shell with chsh, it should automatically login to that shell every time you open a terminal.
If you want to use a different shell temporary, just run that shell directly: "tcsh", "zsh", etc..
If you want to use a particular shell for a script use shebang "#!".
Example -- The following on the first line of a shell script will ensure the script is run with sh (and you can do this for any shell available on your system):
#!/bin/sh
Always check your current shell by using :
echo $0
That way you will get the exact process ( your current shell ) you are running. If you print $SHELL it will return to you the default shell that will be open when you login to the server which unless that's what you need its not reliable.
ubuntu$ echo $SHELL
/bin/bash
ubuntu$ echo $0
-bash
ubuntu$ sh
\[\e[31m\]\u\[\e[m\]$ echo $SHELL
/bin/bash
\[\e[31m\]\u\[\e[m\]$ echo $0
sh
\[\e[31m\]\u\[\e[m\]$
Regards!

Confirmation about pgrep returning itself

I have read several posts here about cases where pgrep 'seems' to return itself even though it never should. The key seems to be the difference between how bash and sh function. Except that in my case, I have confirmed that sh really is a link to bash.
I'm running on SuSE 12 x86_64
/bin/sh is a link to bash
/bin/bash is the real binary
I have a Ruby script which calls pgrep like this:
cmd="/usr/bin/pgrep -lf \"#{target}\""
pidList=`#{cmd}`
I need to use the full command line because I'm actually using an argument to uniquely identify a specific 'java' process.
Now, due to some unrelated foolishness, I almost immediately do a ps -p on each of the pids returned. For a while, this was causing me great grief because the ps would sometimes return nothing. Eventually I was able to catch a case where the ps on the pid returned the pgrep command. But it was the pgrep command itself, not something like sh -c "pgrep -f blah"
To recap:
pgrep never returns itself. But differences in sh vs bash can cause it to show a subshell. But I verified that sh is a link to bash, so there should be no difference in behavior.
What I suspect (and am looking for confirmation for) is that an extra subcommand is being created because of the Ruby backticks and that is what is (only sometimes.. timing issues?) being picked up by the pgrep command.
This has been a real pain and I want to make sure the fix I implement will truly make the problem go away. Given the code I'm working with, I'm either going to
append a | grep -v grep to the end of my command
throw out any results containing 'grep' while looping through the returned results within the Ruby script
I figure #2 is faster, but it still irks me that I have to filter out pgrep itself.
Am I on the right track or do you think something else is at play?
Thanks for your time!
The problem is not in shell flavor: the shell process which calls pgrep also shows among processes (and has the searched string in its full command), so we need to filter it out like this:
pgrep -f target | grep -v $$
The answer is already in the comments to my question, but I figure I'll close this out with an official answer.
The piece of information I was missing is that
When bash is invoked as sh it behaves as a POSIX sh, not bash. – Jörg W Mittag Jan 23 at 23:31
So yes, pgrep was behaving normally. But when you call it from a Ruby script via backticks, you still need to filter out 'pgrep'

Tell if a user has SUed in a shell script?

I have a script which executes a git-pull when I log in. The problem is, if I su to a different user and preserve my environment with an su -lp, the script gets run again and usually gets messed up for various reasons because I'm the wrong user. Is there a way to determine in a shell script whether or not I'm currently SUing? I'm looking for a way that doesn't involve hard coding my username into the script, which is my current solution. I use Bash and ZSH as shells.
You could use the output of the who command with the id command:
WHO=`who am i | sed -e 's/ .*//'`
ID_WHO=`id -u $WHO`
ID=`id -u`
if [[ "$ID" = "$ID_WHO" ]]
then
echo "Not su"
else
echo "Is su"
fi
if test "$(id -u)" = "0";
: # commands executed for root
else
: # commands executed for non root
fi
If you are changing user identities with an suid executable, your real and effective user id will be different. But if use use su (or sudo), they'll both be set to the new user. This means that commands that call getuid() or geteuid() won't be useful.
A better method is to check who owns the terminal the script is being run on. This obviously won't work if the process has detached from it's terminal, but unless the script is being run by a daemon, this is unlikely. Try stat -c %U $(tty). I believe who am i will do the same thing on most Unix-like OSes as well.
You can use "$UID" environment variable.
If its value is ZERO, then the user has SUDOed.. Bcos root as $UID==0
Well.... on linux, if I su to another user the process su is in the new user's process list.
sudo... doesn't leave such pleasant things for you.
I'm using zsh... but I don't think anything in this is shell specific.
if:
%ps | grep " su$"
returns anything, then you're running in an su'd shell.
Note: there is a space before su$ in that to exclude command simply ending in su. Doesn't guard against any custom program/script called su, though.

Resources