Command wont run in script - linux

I am trying to run a command in a shell script but it is not working.
Out side of the script in the shell I can run the following command on the needed host. The file is created with the correct information inside.
sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d > /tmp/expirelist.txt
When the command is run in my script I first ssh over then run the command but I get the following error.
[batch#testserver01 bin]$ checkP.sh
Testserver02
/usr/local/bin/checkP.sh: line 7: /tmp/expirelist.txt: Permission denied
Here is a part of the script. I have tried using ssh -o
#!/bin/bash
for SERVER in `cat /admin/lists/testlist`
do
echo $SERVER
ssh $SERVER sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d > /tmp/expirelist.txt
...
What is causing the Permission denied error?

Don't use hardcoded temporary filenames -- when you do, it means that if one user (say, your development account) already ran this script and left a file named /tmp/expirelist.txt behind, no other user can run the same script.
tempfile=$(mktemp -t expirelist.XXXXXX)
ssh "$SERVER" sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d >"$tempfile"
By using mktemp, you guarantee that each invocation will use a new, distinct, and previously-nonexisting temporary file, preventing any chance of conflict.
By the way -- if you want the file to be created on the remote system rather than the local system, you'd want to do this instead:
ssh "$SERVER" <<'EOF'
tempfile=$(mktemp -t expirelist.XXXXXX)
sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d >"$tempfile"
EOF

I'm not sure about this, but you could be running into an issue with having the 'sudo' within your script. You could try removing the 'sudo' from the script, and running it like this:
$ sudo checkP.sh

Related

How to set a password for all users (Bash Linux)

how do I set a single password for all users in a Linux system? For example, how will I set a password, x, so that it's the password of all users in the system?
I was thinking of a for loop that iterates between each other but then I realised I have no clue on how to go about this.
You could manually change all user accounts in question with the following, it will prompt you for the new password
$ sudo passwd <username>
You could automate this with a script. Or you could use a convoluted command at the command line, which is what I would do. The below example will pull all users from the passwd file, filter out the users that cannot login, and then run a loop to set their password
using cat piped to grep you can get a list of all users and filter out the users with "nologin" or "false" in their config. If you get users that you do not want, change the filter items or add the username to the grep statement to filter them out, separate each filter item with \|
$ cat /etc/passwd | grep -Ev nologin\|false
using awk you can get just the username to print out
$ cat /etc/passwd | grep -Ev nologin\|false | awk '{split($0,a,":");print a[1]}'
running this command in a for loop will let us run a command on each user, to test just echo the username
$ for user in `cat /etc/passwd | grep -Ev nologin\|false | awk '{split($0,a,":");print a[1]}'`; do echo $user; done
the tricky part is passing a password to the passwd command. switch to the root user and then echo the password to the passwd command. Here is an example
$ sudo -i
# (echo 'newpassword'; echo 'newpassword') | passwd <username>
however you do not want the password in your command line history. put the password in a tempfile and then cat it to xargs. As an example, just echo the password using xargs
$ sudo -i
# vi tempfile
enter only one line with the new password
# cat tempfile | xargs -i echo {}
now you'll use xargs to echo to passwd. this is tricky again because you need to run two echo commands correctly, just tell xargs to run the command in a sub shell
$ sudo -i
# cat tempfile | xargs -i /bin/bash -c "(echo '{}'; echo '{}') | sudo passwd <username>"
now add the xargs command in the for loop
$ sudo -i
# for user in `cat /etc/passwd | grep -Ev nologin\|false | awk '{split($0,a,":");print a[1]}'`; do cat tempfile | xargs -i /bin/bash -c "(echo '{}'; echo '{}') | sudo passwd $user"; done
That should be it, let me know if you have questions
I tested this example on ubuntu 20.04 using GNU bash 5.0.17

cant execute command stored in txt file in bash successfully

I have to make ssh request for different nodes based on given IP.
different ssh commands are stored in node.txt as below
0.0.0.0 a ssh -t user#0.0.0.0 sudo -u node0 /path/script.sh
0.0.0.1 b ssh -t user#0.0.0.1 sudo -u node1 /path/script.sh
0.0.0.2 c ssh -t user#0.0.0.2 sudo -u node2 /path/script.sh
I try to grep the needed ssh command like this
comm=$(grep 0.0.0.2 node.txt | grep c | cut -f3)
when I run
status=$($comm)
the following error appears:
/path/script.sh not found
while if I hard coded the command in the script itself it work correctly,
comm='ssh -t user#0.0.0.2 sudo -u node2 /path/script.sh'
status=$($comm)
what could be the problem here?
#Karim Ater
Try the following at your system:
    comm=$(grep 0.0.0.2 node.txt | grep c | cut -f3)
    $ echo $comm
Hence I tried
    comm=$(grep 0.0.0.2 node.txt | grep c | sed "s/.*ssh/ssh/;")
    $ echo $comm
I cannot confirm the contents of node.txt to know related delimiter.
Hence I used sed instead of using cut.

Bash for loops on a remote server

I am attempting to run multiple commands via a bash script on a remote server. specifically, the for loop to be run on the remote server is giving me issues. I suspect it is because I don't know how to properly escape characters or use $().
Below is the code.
ssh (user)#(server) <<EOF
sudo su - (username)
whoami
'for e in $(`ls -lrt /usr/jboss/jbosseap | awk '{print $9}' | grep multichannel`);
do
echo "$e";
done'
Removing user and server names for obvious reasons. Just concentrate on the for loop. when I run that for loop command line (without the $()) its works fine. Just not sure how to nest it in a remote call.
Thanks very much for any and all help!
If you've got a complex script that you're trying to run over ssh you're going to be better off putting that script in a file and piping that file into ssh like:
cat remote_script.sh | ssh user#host
or:
cat remote_script.sh | ssh user#host sudo -u username
And now you don't have to worry about N levels of escaping.
You can run it as below .
here file "list " includes your list of nodes and script should be present in all nodes
for i in $(cat list ) ;do ssh -o StrictHostKeyChecking=no $i "/path/your_script" ;done

grep and tee to identify errors during installation

In order to identify if my installation has errors that I should notice, I am using grep command on the file and write the file using tee because I need to elevate permissions.
sudo grep -inw ${LOGFOLDER}/$1.log -e "failed" | sudo tee -a ${LOGFOLDER}/$1.errors.log
sudo grep -inw ${LOGFOLDER}/$1.log -e "error" | sudo tee -a ${LOGFOLDER}/$1.errors.log
The thing is that the file is created even if the grep didn't find anything.
Is there any way I can create the file only if the grep found a match ?
Thanks
You may replace tee with awk, it won't create file if there is nothing to write to it:
... | sudo awk "{print; print \$0 >> \"errors.log\";}"
But such feature of awk is rarely used. I'd rather remove empty error file if nothing is found:
test -s error.log || rm -f error.log
And, by the way, you may grep for multiple words simultaneously:
grep -E 'failed|error' ...

Why can't this script execute the other script

This script looks for all users that have the string RECHERCHE inside them. I tried running it in sudo and it worked, but then stopped at line 8 (permission denied). Even when removing the sudo from the script, this issue still happens.
#!/bin/bash
#challenge : user search and permission rewriting
echo -n "Enter string to search : "
read RECHERCHE
echo $(cat /etc/passwd | grep "/home" | cut -d: -f5 | grep -i "$RECHERCHE" | sed s/,//g)
echo "Changing permissions"
export RECHERCHE
sudo ./challenge2 $(/etc/passwd) &
The second script then changes permissions of each file belonging to each user that RECHERCHE found, in the background. If you could help me figure out what this isn't doing right, it would be of great service. I
#!/bin/bash
while read line
do
if [-z "$(grep "/home" | cut -d: -f5 | grep -i "$RECHERCHE")" ]
then
user=$(cut -f: -f1)
file=$(find / -user $(user))
if [$(stat -c %a file) >= 700]
then
chmod 700 file 2>> /home/$(user)/challenge.log
fi
if [$(stat -c %a file) < 600]
then
chmod 600 file 2>> /home/$(user)/challenge.log
fi
umask 177 2>> /home/$(user)/challenge.log
fi
done
I have to idea what I'm doing.
the $(...) syntax means command substitution, that is: it will be replaced by the output of the command within the paranthesis.
since /etc/passwd is no command but just a text-file, you cannot execute it.
so if you want to pass the contents of /etc/passwd to your script, you would just call it:
./challenge2 < /etc/passwd
or, if you need special permissions to read the file, something like
sudo cat /etc/passwd | ./challenge2
also in your challenge2 script, you are using $(user) which is wrong as you really only want to expand the user variable: use curly braces for this, like ${user}
/etc/passwd?
not what you were asking, but you probably should not read /etc/passwd directly anyhow.
if you want to get a list of users, use the following command:
$ getent passwd
this will probably give you more users than those stored in /etc/passwd, as your system might use other PAM backends (ldap,...)

Resources