su command in shell script - linux

I have a script which copies a file, then untar and install it (agent-service) on multiple systems (IPs are read from systems.txt file). In the script, I wanted to start the agent-service as user "test". However after the script execution, when I check the target system, the agent-service is shown as running as "root" user. What could be wrong here? Am I not using su command correct within the script?
~]# ps -ef | grep agent-service
root 23511 15196 0 02:12 pts/3 00:00:00 agent-service
Script>
#!/bin/bash
export AGENT=linux-5.8.1.tar.gz
while read host; do
scp $AGENT root#$host:/opt
ssh -n root#$host 'cd /opt/linux;
tar zxvf linux-5.8.1.tar.gz;
mkdir /opt/hyperic;
useradd -m test;
chown -R test:test /opt/linux;
su - test;
/opt/linux/agent-service start'
done < systems.txt

Using su as you do here spawns a new shell that has nothing to do thus exits immediately.
Either pass the command to su:
su - test -c /opt/linux/agent-service start
Or use sudo in a similar manner:
sudo -u test /opt/linux/agent-service start

Related

change user and run ssh instruction in 1 line

I'm trying to change my user to one that doesn't need password to run ssh instructions and then do exactly that, run an ssh instruction. What I have now is:
sudo su - testUser ssh testUser#server2 'cat /home/randomUser/hola.txt'
But I'm getting the answer:
/usr/bin/ssh: /usr/bin/ssh: cannot execute binary file
if I put the instructions in a different file called testit like this:
ssh testUser#server2
cat /home/randomUser/hola.txt
and I run:
sudo su - testUser < testit
it works!, but I need to use the one line instruction, someone know what should I change to make it work?
sudo su - testUser
why don't you use just sudo -u testUser as it is supposed to be used?
But anyway, manual pages for the tools you are using is a good start. For sudo:
sudo [...] [command]
This looks good and fits into your example.
For su:
su [options] [username]
Ola ... su does not have any argument command, unless you provide also -c switch, which is written also in the manual page. And it is [option], so it should come in front of [username]! Something like this should do the job:
sudo su -l -c "ssh testUser#server2 'cat /home/randomUser/hola.txt'" testUser
but as I already mentioned, it can be significantly simplified by using sudo only:
sudo -i -u testUser "ssh testUser#server2 'cat /home/randomUser/hola.txt'"

Use source with script that contains sudo command

I have a script that copies files between servers. I am using the lsof command to make sure that the file is not being written to before being moved. The user running the script and the user writing to the file are different, so I need to sudo to the file owner. Here is the relevant line in the sudoers file :
userA ALL=(userB:userB) NOPASSWD: ALL
In the main script (ran as userA), I have tried calling sudo then the subscript containing the lsof command:
sudo su - userB -c 'source ./getOpenFiles.sh'
getOpenFiles.sh has this one line:
#!/bin/bash
lsofResult=$(/usr/sbin/lsof "${sourcePath}")
I have also tried calling the subscript:
source ./getOpenFiles.sh
Then have the first line of the subscript be the sudo:
#!/bin/bash
sudo su - banjobs
lsofResult=$(/usr/sbin/lsof "${sourcePath}")`.
Neither solution is working.
What you actually want is something more like:
lsofResult=$(sudo -u banjobs lsof "${sourcePath}")
Let's go over why the other approaches didn't work one-at-a-time:
Running source under sudo su -c
sudo su - userB -c 'source ./getOpenFiles.sh'
...uses sudo to run su, which runs sh -c 'source ./getOpenFiles.sh'. This doesn't work for several independent reasons:
sh -c 'source ./getOpenFiles.sh' relies on the source keyword being available in /bin/sh, but this is a bash extension.
Even if your /bin/sh is provided by bash, this still defeats the purpose of using source: By starting a new copy of /bin/sh and sourcing your script into that, you're defining the variable in the new shell, not in the original shell that started sudo su.
Running sudo su - banjobs, followed by lsofResult=$(/usr/sbin/lsof "${sourcePath}")
...means that lsofResult=$(...) doesn't run until after sudo su - banjobs exits. If sudo su - banjobs has exited, then the current user isn't banjobs any more, so the sudo command has no effect whatsoever on the lsof.
Demonstrating, in detail, how to test this (for folks who don't have a banoff or userB account on their system):
# place relevant contents in sourceme.bash
# switching from lsof to fuser for this test since OS X lsof does not accept a directory
# as an argument.
cat >sourceme.bash <<'EOF'
lsofResult=$(sudo -u root fuser "${sourcePath}" 2>&1)
EOF
# set sourcePath in the outer shell
sourcePath=$PWD
source sourceme.bash
declare -p lsofResult
...yields, on my system, output akin to the following:
declare -- lsofResult="/Users/chaduffy/tmp: 17165c 17686c 17687c 17688c 17689c 17690c"
...showing that the code in question did in fact work as described.

How can I Enter into postgres bash command line and exit using shell script?

I'm beginner in writing script in linux. Can anyone please help!
From terminal I enter into postgres bash command line by typing:
[root#localhost Desktop]# su - postgres
-bash-3.2$
then I can create user,db from there and I can exit by typing "exit" command.
How can I do this by script? I've written a scrip but that does enter into bash but doesn't run the commands. I want to enter into bash, create a user & db then exit. My scripts concept is given below:
#!/bin/bash
createuser -P -s -e asterisk
createdb --owner=asterisk asterisk2
You should run your script this way:
su -c myscript.sh postgres
That is, run myscript.sh (or whatever it's called) as the postgres user. No need for an interactive prompt, which is what - was giving you.
Try this:
su postgres -c "createuser -P -s -e asterisk && createdb --owner=asterisk asterisk2"

How to run sudo under su?

I have this:
su $username -c ./script.sh
The problem is that within script I have 'sudo' commands and they says me
sudo: no tty present and no askpass program specified
How to do this right?
UPD: I need both sudo and su. What I need to do is run script as USER $username and be able to run certain commands within script as root (for example, pacman -S)
SOLUTION: I've added NOPASSWD option to /etc/sudoers before running script and delete this entry using sed after script finished.
First set chmod +x to your scripts
try:
#!/bin/bash
echo "hello"
su - <your-user> -c /path/to/script.sh
echo "good bye"
UPDATE:
You should find a way to force bash to use pseudo-tty
Force pseudo-tty allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can be very useful, e.g. when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty.
If the user is not as sudoers do the following steps:
This is what you need to do in /etc/sudoers:
# User privilege specification
root ALL=(ALL:ALL) ALL
newuser ALL=(ALL:ALL) ALL
you have also ways to do:
you can pipe password if it has password:
echo "yourpassword" | sudo -S
OR
You can run the following script:
#!/usr/bin/expect -f
spawn sudo -s <<EOF
expect "assword for username:"
send -- "user-password\r"
expect eof
Also you can do that:
sudo -kS bash - << EOF
password
whoami
echo "Not a good idea to have a password encoded in plain text"
EOF

Execute a shell script in current shell with sudo permission

To execute a shell script in current shell, we need to use a period . or a source command. But why does it not work with a sudo permission?
I have a script with execute permission called setup.sh. When I use a period, I get this:
$ sudo . ./setup.sh
sudo: .: command not found
The source command also produces a similar error. Am I missing out something? What should I do to run the script with sudo permission in the same/current shell?
I'm not sure if this breaks any rules but
sudo bash script.sh
seems to work for me.
What you are trying to do is impossible; your current shell is running under your regular user ID (i.e. without root the access sudo would give you), and there is no way to grant it root access. What sudo does is create a new *sub*process that runs as root. The subprocess could be just a regular program (e.g. sudo cp ... runs the cp program in a root process) or it could be a root subshell, but it cannot be the current shell.
(It's actually even more impossible than that, because the sudo command itself is executed as a subprocess of the current shell -- meaning that in a sense it's already too late for it to do anything in the "current shell", because that's not where it executes.)
I think you are confused about the difference between sourcing and executing a script.
Executing a script means creating a new process, and running the program. The program can be a shell script, or any other type of program. As it is a sub process, any environmental variables changed in the program will not affect the shell.
Sourcing a script can only be used with a bash script (if you are running bash). It effectively types the commands in as if you did them. This is useful as it lets a script change environmental variables in the shell.
Running a script is simple, you just type in the path to the script. . is the current directory. So ./script.sh will execute the file script.sh in the current directory. If the command is a single file (eg script.sh), it will check all the folders in the PATH variable to find the script. Note that the current directory isn't in PATH, so you can't execute a file script.sh in the current directory by running script.sh, you need to run ./script.sh (unless the current directory is in the PATH, eg you can run ls while in the /bin dir).
Sourcing a script doesn't use the PATH, and just searches for the path. Note that source isn't a program - otherwise it wouldn't be able to change environmental variables in the current shell. It is actually a bash built in command. Search /bin and /usr/bin - you won't find a source program there. So to source a file script.sh in the current directory, you just use source script.sh.
How does sudo interact with this? Well sudo takes a program, and executes it as root. Eg sudo ./script.sh executes script.sh in a sub process but running as root.
What does sudo source ./script.sh do however? Remember source isn't a program (rather a shell builtin)? Sudo expects a program name though, so it searches for a program named source. It doesn't find one, and so fails. It isn't possible to source a file running as root, without creating a new subprocess, as you cannot change the runner of a program (in this case, bash) after it has started.
I'm not sure what you actually wanted, but hopefully this will clear it up for you.
Here is a concrete example. Make the file script.sh in your current directory with the contents:
#!/bin/bash
export NEW_VAR="hello"
whoami
echo "Some text"
Make it executable with chmod +x script.sh.
Now observe what happens with bash:
> ./script.sh
david
Some text
> echo $NEW_VAR
> sudo ./script.sh
root
Some text
> echo $NEW_VAR
> source script.sh
david
Some text
> echo $NEW_VAR
hello
> sudo source script.sh
sudo: source: command not found
Basically sudo expects, an executable (command) to follow & you are providing with a .
Hence the error.
Try this way $ sudo setup.sh
If you really want to "ExecuteCall a shell script in current shell with sudo permission" you can use exec to...
replace the shell with a given program (executing it, not as new process)
I insist on replacing "execute" with "call" because the former has a meaning that includes creating a new process and ID, where the latter is ambiguous and leaves room for creativity, of which I am full.
Consider this test case and look closely at pid 1337
# Don't worry, the content of this script is cat'ed below
$ ./test.sh -o foo -p bar
User ubuntu is running...
PID TT USER COMMAND
775 pts/1 ubuntu -bash
1408 pts/1 ubuntu \_ bash ./test.sh -o foo -p bar
1411 pts/1 ubuntu \_ ps -t /dev/pts/1 -fo pid,tty,user,args
User root is running...
PID TT USER COMMAND
775 pts/1 ubuntu -bash
1337 pts/1 root \_ sudo ./test.sh -o foo -p bar
1412 pts/1 root \_ bash ./test.sh -o foo -p bar
1415 pts/1 root \_ ps -t /dev/pts/1 -fo pid,tty,user,args
Take 'exec' out of the command and this script would get cat-ed twice. (Try it.)
#!/usr/bin/env bash
echo; echo "User $(whoami) is running..."
ps -t $(tty) -fo pid,tty,user,args
if [[ $EUID > 0 ]]; then
# exec replaces the current process effectively ending execution so no exit is needed.
exec sudo "$0" "$#"
fi
echo; echo "Take 'exec' out of the command and this script would get cat-ed twice. (Try it.)"; echo
cat $0
Here is another test using sudo -s
$ ps -fo pid,tty,user,args; ./test2.sh
PID TT USER COMMAND
10775 pts/1 ubuntu -bash
11496 pts/1 ubuntu \_ ps -fo pid,tty,user,args
User ubuntu is running...
PID TT USER COMMAND
10775 pts/1 ubuntu -bash
11497 pts/1 ubuntu \_ bash ./test2.sh
11500 pts/1 ubuntu \_ ps -fo pid,tty,user,args
User root is running...
PID TT USER COMMAND
11497 pts/1 root sudo -s
11501 pts/1 root \_ /bin/bash
11503 pts/1 root \_ ps -fo pid,tty,user,args
$ cat test2.src
echo; echo "User $(whoami) is running..."
ps -fo pid,tty,user,args
$ cat test2.sh
#!/usr/bin/env bash
source test2.src
exec sudo -s < test2.src
And a simpler test using sudo -s
$ ./exec.sh
bash's PID:25194 user ID:7809
systemd(1)───bash(23064)───bash(25194)───pstree(25196)
Finally...
bash's PID:25199 user ID:0
systemd(1)───bash(23064)───sudo(25194)───bash(25199)───pstree(25201)
$ cat exec.sh
#!/usr/bin/env bash
pid=$$
id=$(id -u)
echo "bash's PID:$pid user ID:$id"
pstree -ps $pid
# the quoted EOF is important to prevent shell expansion of the $...
exec sudo -s <<EOF
echo
echo "Finally..."
echo "bash's PID:\$\$ user ID:\$(id -u)"
pstree -ps $pid
EOF
It works without "sudo".
bash setup.sh
Even the first answer is absolutely brilliant, you probably want to only run script under sudo.
You have to specify the absolute path like:
sudo /home/user/example.sh
sudo ~/example.sh
(both are working)
THIS WONT WORK!
sudo /bin/sh example.sh
sudo example.sh
It will always return
sudo: bin/sh: command not found
sudo: example.sh: command not found
The answers here explain why it happens but I thought I'd add my simple way around the issue. First you can cat the file into a variable with sudo permissions. Then you can evaluate the variable to execute the code in the file in your current shell.
Here is an example of reading and executing an .env file (ex Docker)
sensitive_stuff=$(sudo cat ".env")
eval "${sensitive_stuff}"
echo $ADMIN_PASSWORD
Easiest method is to type:
sudo /bin/sh example.sh

Resources