How to change file permission while doing ssh in shell - linux

I am using the below codes to change some file permissions:
encrypt=`sed -n '/:/,$p' $FILE_PATH_1 | cut -d':' -f2 | tr -d ' '`
local listOfPasswordChangeWS=`$SMANAGER_SCRIPT status service PasswordChangeWS | cut -f 2 -d ":"`
for node in $listOfPasswordChangeWS ; do
ssh -q $i "cp /opt/oss/NSN-mf_swp/smx/mf-conf/was-cred.properties /opt/oss/NSN-mf_swp/smx/mf-conf/was-cred.properties.original"
ssh -q $i "sed -i '/Password/c\com.ibm.CORBA.loginPassword=ENC($encrypt)' /opt/oss/NSN-mf_swp/smx/mf-conf/was-cred.properties "
**ssh -q $i "chown -c omc:sysop /opt/oss/NSN-mf_swp/smx/mf-conf/was-cred.properties ; chmod 640 /opt/oss/NSN-mf_swp/smx/mf-conf/was-cred.properties"**
# INCR=$?
INCR=$?
if [ "INCR" == "0" ] ; then
NewIncr++
fi
done
I want to check the exit status but since it is in for loop i am not able to get value 0 or 1 instead it is returning value 255. My query is:
1. How can I check the exit status of chown -c command (Remember i am doing ssh)
2. How can I check whether my file permission has been changed to omc:sysop

Try this:
if ssh $HOST 'chown -c omc:sysop /opt/oss/NSN-mf_swp/smx/mf-conf/was-cred.properties ; chmod 640 /opt/oss/NSN-mf_swp/smx/mf-conf/was-cred.properties' < /dev/null
if [ $? -eq 0 ]; then
echo SUCCESS
else
echo FAIL
fi

Related

Can't parse a string with brace expansion operations into a command

have some problem with shell script.
In our office we set up only few commands, that available for devs when they are trying ssh to server. It is configured with help of .ssh/authorized_keys file and available command for user there is bash script:
#!/bin/sh
if [[ $1 == "--help" ]]; then
cat <<"EOF"
This script has the purpose to let people remote execute certain commands without logging into the system.
For this they NEED to have a homedir on this system and uploaded their RSA public key to .ssh/authorized_keys (via ssh-copy-id)
Then you can alter that file and add some commands in front of their key eg :
command="/usr/bin/dev.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
The user will do the following : ssh testuser#server tail testserver.example.com/2017/01/01/user.log
EOF
exit 0;
fi
# set global variable
set $SSH_ORIGINAL_COMMAND
# set the syslog path where the files can be found
PATH="/opt/syslog/logs"
# strip ; or any other unwanted signs out of the command, this prevents them from breaking out of the setup command
if [[ $1 != "" ]]; then
COMMAND=$1
COMMAND=${COMMAND//[;\`]/}
fi
if [[ $2 != "" ]]; then
ARGU1=$2
ARGU1=${ARGU1//[;\`]/}
fi
if [[ $3 != "" ]]; then
ARGU2=$3
ARGU2=${ARGU2//[;\`]/}
fi
if [[ $4 != "" ]]; then
ARGU3=$4
ARGU3=${ARGU3//[;\`]/}
fi
# checking for the commands
case "$COMMAND" in
less)
ARGU2=${ARGU1//\.\./}
FILE=$PATH/$ARGU1
if [ ! -f $FILE ]; then
echo "File doesn't exist"
exit 1;
fi
#echo " --------------------------------- LESS $FILE"
/usr/bin/less $FILE
;;
grep)
if [[ $ARGU2 == "" ]]; then
echo "Pls give a filename"
exit 1
fi
if [[ $ARGU1 == "" ]]; then
echo "Pls give a string to search for"
exit 1
fi
ARGU2=${ARGU2//\.\./}
FILE=$PATH/$ARGU2
/usr/bin/logger -t restricted-command -- "------- $USER Executing grep $ARGU1 \"$ARGU2\" $FILE"
if [ ! -f $FILE ]; then
echo "File doesn't exist"
/usr/bin/logger -t restricted-command -- "$USER Executing $#"
exit 1;
fi
/bin/grep $ARGU1 $FILE
;;
tail)
if [[ $ARGU1 == "" ]]; then
echo "Pls give a filename"
exit 1
fi
ARGU1=${ARGU1//\.\./}
FILE=$PATH/$ARGU1
if [ ! -f $FILE ]; then
echo "File doesn't exist"
/usr/bin/logger -t restricted-command -- "$USER Executing $# ($FILE)"
exit 1;
fi
/usr/bin/tail -f $FILE
;;
cat)
ARGU2=${ARGU1//\.\./}
FILE=$PATH/$ARGU1
if [ ! -f $FILE ]; then
echo "File doesn't exist"
exit 1;
fi
/bin/cat $FILE
;;
help)
/bin/cat <<"EOF"
# less LOGNAME (eg less testserver.example.com/YYYY/MM/DD/logfile.log)
# grep [ARGUMENT] LOGNAME
# tail LOGNAME (eg tail testserver.example.com/YYYY/MM/DD/logfile.log)
# cat LOGNAME (eg cat testserver.example.com/YYYY/MM/DD/logfile.log)
In total the command looks like this : ssh user#testserver.example.com COMMAND [ARGUMENT] LOGFILE
EOF
/usr/bin/logger -t restricted-command -- "$USER HELP requested $#"
exit 1
;;
*)
/usr/bin/logger -s -t restricted-command -- "$USER Invalid command $#"
exit 1
;;
esac
/usr/bin/logger -t restricted-command -- "$USER Executing $#"
The problem is next:
when i try to exec some command, it takes only first argument, if i do recursion in files by using {n,n1,n2} - it doesn't work:
[testuser#local ~]$ ssh testuser#syslog.server less srv1838.example.com/2017/02/10/local1.log |grep 'srv2010' | wc -l
0
[testuser#local ~]$ ssh testuser#syslog.server less srv2010.example.com/2017/02/10/local1.log |grep 'srv2010' | wc -l
11591
[testuser#local ~]$ ssh testuser#syslog.server less srv{1838,2010}.example.com/2017/02/10/local1.log |grep 'srv2010' | wc -l
0
[testuser#local ~]$ ssh testuser#syslog.server less srv{2010,1838}.example.com/2017/02/21/local1.log |grep 'srv2010' | wc -l
11591
Could someone help me, how can i parse\count command arguments to make it work?
Thank you and have a nice day!
The number of arguments for a bash script would be $#. As a quick example:
#!/bin/bash
narg=$#
typeset -i i
i=1
while [ $i -le $narg ] ; do
echo " $# $i: $1"
shift
i=$i+1
done
gives, for bash tst.sh a b {c,d}
4 1: a
3 2: b
2 3: c
1 4: d
In your script, the command to execute (cat, less, ...) gets explicitly only the second argument to the script. If you want to read all arguments, you should do something like this (note: only a hint, removed all sorts of checks etc..)
command="$1"
shift
case $command in
(grep) pattern="$1"
shift
while [ $# -gt 0 ] ; do
grep "$pattern" "$1"
shift
done
;;
esac
note: added some quotes as comment suggested, but, being only a hint, you should carefully look at quoting and your checks in your own script.
Less command working now:
case "$COMMAND" in
less)
if [[ $ARGU1 == "" ]]; then
echo "Pls give a filename"
exit 1
fi
FILES_LIST=${#:2}
FILE=(${FILES_LIST//\.\./})
for v in "${FILE[#]}";do
v=${v//[;\']/}
if [ ! -f $v ]; then
echo "File doesn't exist"
fi
/usr/bin/less $PATH/$v
done;;
tail command works too with 2 and more files, but i can't execute tail -f command on two files unfortunately.

Verify account creation from text file in bash script

I am trying to output which accounts have been successfully created from a text file and which haven't. I would also like to output the number of successfully created accounts. I currently the get the following error: grep: 3: No such file or directory. The script and text file and saved in the same folder. I have use the following commands in my script.
file=users.txt
verify =grep "verify" $file |cut -f2 -d:`
cat /etc/passwd | grep $verify
echo -e "\nYou have Currently"
cat /etc/passwd | grep $verify |wc -l;
echo "users added from your Text File"
Edit:
#!/bin/bash
ROOT_UID=0 #The root user has a UID of 0
if [ "$UID" -ne "$ROOT_UID" ]; then
echo "**** You must be the root user to run this script!****"
exit
fi
clear
echo
echo "######################################################"
echo "##### Batch script to automate creation of users #####"
echo -e "######################################################\n"
while true;
do
file=notvalid
while [ $file == "notvalid" ]
do
#echo "repeat $repeat"
#echo -e "\n"
echo -n "Please enter import filename:"
read filename
echo -e "\r"
exists=0
if [ -e $filename ]; then
file=valid
while IFS=":" read firstname lastname userid password group
do
egrep -i "^$userid:" /etc/passwd &>/dev/null
if [ $? -eq 0 ]; then
exists=$((exists+1))
#echo -e "${firstname} ${lastname} already exists on the system"
#grep ${userid} /etc/passwd
aname=$( getent passwd "$userid" | cut -d: -f3)
echo "Account Exists: $aname"
euserid=$( getent passwd "$userid" | cut -d: -f1)
echo "User ID: $userid"
homedir=$( getent passwd "$userid" | cut -d: -f6)
echo "Home Directory: $homedir"
usershell=$( getent passwd "$userid" | cut -d: -f7)
echo "User Shell: $usershell"
g=$( id -Gn "$userid")
echo "Groups: $g"
echo -e "\r"
else
egrep -i "^$group:" /etc/group &>/dev/null
if [ $? -eq 1 ]; then
/usr/sbin/addgroup ${group} &>/dev/null
fi
useradd -d /home/"${userid}" -m -s /bin/bash -c \
"${firstname}${lastname}" -g "${group}" "${userid}"
echo "Creating Account: ${firstname} ${lastname}"
nuserid=$( getent passwd "$userid" | cut -d: -f1)
echo "Creating User ID: ${nuserid}"
{ echo ${password}; echo ${password}; } | sudo passwd ${userid} > /dev/null 2>&1
echo "Creating Password: ${password}"
echo "Creating Home Directory: /home/${userid}"
echo "Creating User Shell: /bin/bash"
echo -e "Assigning Group: ${group}\n"
fi
done < $filename
else
echo -e "##### CANNOT FIND OR LOCATE FILE #####"
fi
verify=`grep "verify" /home/pi/$filename | cut -f3 -d:`
echo "$verify"
count=0
for id in $verify
do grep -wo ^$id /etc/passwd && count=$((count+1))
done
echo $count users added from your text file
echo these are not added:
for id in $verify
do grep -wq ^$id /etc/passwd || echo $id
done
while true
do
echo -n "Create additional accounts [y/n]: "
read opt
if [[ $opt == "n" || $opt == "y" ]];then
break
else
echo "Invalid Input"
fi
done
if [ $opt = "n" ]; then
clear
break
else
clear
fi
done
You were almost there.
The main issue with your approach is that you try to search for multiple accounts at once with grep. The variable verify has multiple userids so you need to process it one by one.
file=users.txt
verify=`grep "verify" $file | cut -f2 -d:`
count=0
for id in $verify
do grep -wo ^$id /etc/passwd && count=$((count+1))
done
echo $count users added from your text file
echo these are not added:
for id in $verify
do grep -wq ^$id /etc/passwd || echo $id
done
The for loop will take each element in your verify variable into id and search with grep (-w matches only whole words, not fragments, ^ matches the beginning of line and -o outputs only the matching word not the whole line).
We count the number of matches in the count variable. Alternative approach to run the for loop twice and pipe the second one to wc -l as you did.
&& operator means it will increase count if the previous command found a match (the return code of grep was 0).
The next loop will not print matching ids (-q), and will echo id if grep did not found a match (the return code was not 0). This is achieved with the || operator.
One last note on iteration of a list: if the members can contain spaces (unlike userids), you should use ${verify[#]} (this is a bash-ism) instead of $verify .
And forget this: cat /etc/passwd | grep pattern, use grep pattern /etc/passwd instead.

Linux bash read from a file then adduser to linux

I want to add linux users then i want to restrict them as hard as possible. (noshell etc) from a file called users.
This is my code but not working:
while read line
do
input = echo ($input | tr ":" "\n")
#!/bin/bash
# Script to add a user to Linux system
if [ $(id -u) -eq 0 ]; then
if [ $? -eq 0 ]; then
echo "$username exists!"
exit 1
else
pass=$(perl -e 'print crypt($ARGV[0], "password")' $input[1)
useradd -m -p $input[1] $input[0]
[ $? -eq 0 ] && echo "User has been added to system!" || echo "Failed to add a user!"
fi
else
echo "Only root may add a user to the system"
exit 2
fi
done < /var/www/users
Then i want to restrict their accounts with noshell. (but i know how can i do. But i cant separate the input from the file correctly :/)
input(users):
john:lol
rambo:sanyi
cula:kari
Thank you very much!
I think, following script will do:
#!/bin/bash
USERS=`cat /etc/passwd | cut -d: -f1`
if [ `id -u` -ne 0 ]
then
echo "Login as Root"
else
while read line
do
USER=`echo $line | cut -d ":" -f1`
PASS=`echo $line | cut -d ":" -f2`
echo $USERS | grep "${USER}" > /dev/null
if [ $? -eq 0 ]
then
echo "Username ${USER} Exists!"
else
password=`perl -e 'print crypt("${PASS}", "salt")', "\n"`
useradd -p "${password}" ${USER}
echo "User ${USER} created!"
fi
i+=1
done < /var/www/users
fi

Using Local and Remote Variable in SSH

I have written a shell script which SSH to a remote host and does some processing. The code that executes remotely has to to use the local variables which are read from the properties file. My code is as below. The below code is not executed properly. Its giving an error that
-printf: unknown primary or command.
Please help me with this.
Note: datadir, username and ftphostname are defined in properties file.
. config.properties
ssh $username#$ftphostname << EOF
filelist=;
filelist=($(find "$datadir" -type f -printf "%T# %p\n"| sort -n | head -5 | cut -f2- -d" "));
filecount=\${#filelist[#]};
while [ \${#filelist[#]} -gt 0 ]; do
checkCount=;
filesSize=$(wc -c \${filelist[#]}|tail -n 1 | cut -d " " -f1) ;
if [ "\$filesSize" == "\$fileSizeStored" ]; then
fileSizeStored=0;
printf "\n*********** \$(date) ************* " >> /home/chisan/logs/joblogs.log;
echo "Moved below files" >> /home/joblogs.log;
for i in "\${filelist[#]}"
do
# echo "file is \$i"
checkCount=0;
mv \$i /home/outputdirectory/;
if [ $? -eq 0 ]; then
echo "File Moved to the server: \$i" >> /home/joblogs.log;
else
echo "Error: Failed to move file: \$i" >> /home/joblogs.log;
fi
done
filelist=($(find "$datadir" -type f -printf '%T# %p\n' | sort -n | head -5 | cut -f2- -d" "));
else
((checkCount+=1));
sleep 4;
fileSizeStored=\$filesSize;
fi
done
EOF
But this one works
#ssh to remote system and sort the files and fetch the files which are copied first(based on modification time)
ssh -o StrictHostKeyChecking=no user#server 'filelist=($(find /home/data -type f - printf "%T# %p\n" | sort -n | head -5 | cut -f2- -d" "));
# filelist array variable holds the file names which have the oldest modification date.
#check the directory until it has atleast one file.
while [ ${#filelist[#]} -gt 0 ]; do
filesSize=$(wc -c "${filelist[#]}"|tail -n 1 | cut -d " " -f1) ;
#filesSize contains the total size of the files that are in the filelist array.
if [ -e "$HOME/.storeFilesSize" ]; then
fileSizeStored=$(cat "$HOME/.storeFilesSize");
if [ "$filesSize" == "$fileSizeStored" ]; then
echo "Moved below files" >> /home/joblogs.log;
for i in "${filelist[#]}"
do
mv "$i" /home/dmpdata1 &>/dev/null;
if [ $? -eq 0 ]; then
echo "File Moved to the server: $i" >>/home/joblogs.log;
else
echo "Error: Failed to move file: $i" >>/home/joblogs.log;
fi
done
filelist=($(find /home/data -type f -printf "%T# %p\n" | sort -n | head -5 | cut -f2- -d" "));
else
sleep 4;
echo "$filesSize" > "$HOME/.storeFilesSize";
fi
else
echo "creating new file";
echo "$filesSize" > "$HOME/.storeFilesSize";
fi
done'
I will not answer directly (ie, not with your specific needs and actions), but give a generic possibility and how to use local and remote variables :
Your master script should create a "specific script", locally.
And then copy it over and run it remotely (with additionnal arguments if needed)
Generic example of Master script :
#local Master script: This script creates a local script,
# and then copy it to remotehost and start it
#Some local variables will be defined here.
#They can be used below, and will be replaced by their value locally
localvar1="...."
localvar2="...."
#now we create the script
cat > /tmp/localscript_to_be_copied_to_remote.sh <<EOF
#remote_script
for i in ..... ; do
something ;
somethingelse
done
......
.....
EOF
#in the above, each time you used "$localvar1" or "$localvar2", the script
# /tmp/localscript_to_be_copied_to_remote.sh will instead have their values,
# as the local shell will replace them on the fly during the cat > ... <<EOF .
# if you want to have some remotevariable "as is" (and not as their local value) in the script,
# write them as "\$remotevariable" there, instead of "$remotevariable", so the local shell
# won't interpret them during the 'cat', and the script will receive "$remotevariable"
# as is, instead of its local value.
#then you copy the script:
scp -p /tmp/localscript_to_be_copied_to_remote.sh user#remotehost:/some/dir/name.sh
#and you run it:
# UNCOMMENT the line below ONLY when /tmp/localscript_to_be_copied_to_remote.sh is correct!
# ssh user#remotehost "/some/dir/name.sh" #+ maybe some parameters as well
#end of local Master script.
You then run "local Master script" and have it create the tmp file locally (which you can check to make sure it is supposed to be like this on the remote host), and then copy it remotely and execute it.
Specific example of master script :
#!/bin/bash
local1="/tmp /var /usr /home" # this will be the default name of the dirs (on the remote host)
# that the script will print the size of (+ any additionnal parameters)
cat > /tmp/printsizes.bash <<EOF
#!/bin/bash
for dir in $local1 "\$#" ; do
du -ks "\$dir"
done
EOF
scp -p /tmp/printsizes.bash user#remotehost:/tmp/print_dir_sizes.bash
ssh user#remotehost "/tmp/print_dir_sizes.bash /etc /root"
This (weird...) example will create a LOCAL script containing:
#!/bin/bash
for dir in /tmp /var /usr /home "$#" ; do
du -ks "$dir"
done
And will execute it with:
ssh user#remotehost "/tmp/print_dir_sizes.bash /etc /root"
so it will do remotely:
for dir in /tmp /var /usr /home /etc /root ; do
du -ks "$dir"
done
I hope it helps to see how to use local and remote variables...

How to check for a folder in 2 machines using shell script?

I am working on a shell script which I need to run on machineX. It will check for a certain folder which is in this format YYYYMMDD inside this folder MAPPED_LOCATION in other two machines - machineP and machineQ. So the path will be like this in both machineP and machineQ-
/bat/testdata/t1_snapshot/20140311
And inside the above folder path, there will be some files inside in it. Below is my shell script -
#!/bin/bash
readonly MACHINES=(machineP machineQ)
readonly MAPPED_LOCATION=/bat/testdata/t1_snapshot
readonly FILE_TIMESTAMP=20140311
# old code which I was using to get the latest folder inside each machine (P and Q)
dir1=$(ssh -o "StrictHostKeyChecking no" david#${MACHINES[0]} ls -dt1 "$MAPPED_LOCATION"/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] | head -n1)
dir2=$(ssh -o "StrictHostKeyChecking no" david#${MACHINES[1]} ls -dt1 "$MAPPED_LOCATION"/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] | head -n1)
dir3=$MAPPED_LOCATION/$FILE_TIMESTAMP # /bat/testdata/t1_snapshot/20140311
echo $dir1
echo $dir2
echo $dir3
if dir3 path exists in both the machines (P and Q) and number of files is greater than zero in each machine
then
# then do something here
echo "Hello World"
else
# log an error - folder is missing or number of files is zero in which servers or both servers
fi
Noow what I am supposed to do is - If this path exists /bat/testdata/t1_snapshot/20140311 in both of the machines and number of files are greater than zero in both of the machines, then do somethting. Else if the folder is missing in any of the servers or number of files is zero in any of ther servers, I will exit out of the shell script with non zero status and a message with an actual error.
How can I do this in shell script?
Update:-
for machine in $MACHINES; do
dircheck=($(ssh -o "StrictHostKeyChecking no" david#${machine} [[ ! -d "$dir3" ]] \&\& exit 1 \; ls -t1 "$dir3"))
#On the ssh command, we exit 1 if the folder doesn't exist. We check the return code with `$?`
if [[ $? != 0 ]] ;then
echo "Folder doesn't exist on $machine";
exit 1
fi
# check number of files retrieved
if [[ "${dircheck[#]}" = 0 ]] ;then
echo "0 Files on server $machine";
exit 1
fi
#all good for $machine here
done
echo "Everything is Correct"
If I am adding a new empty folder 20140411 inside machineP and then execute the above script, it always prints out -
echo "Everything is Correct"
Infact, I didn't added any folder in machineQ. Not sure what is the problem?
Another Update-
I have created an empty folder 20140411 in machineP only. And then I ran the script in debug mode -
david#machineX:~$ ./test_file_check_1.sh
+ FILERS_LOCATION=(machineP machineQ)
+ readonly FILERS_LOCATION
+ readonly MEMORY_MAPPED_LOCATION=/bexbat/data/be_t1_snapshot
+ MEMORY_MAPPED_LOCATION=/bexbat/data/be_t1_snapshot
+ readonly FILE_TIMESTAMP=20140411
+ FILE_TIMESTAMP=20140411
+ dir3=/bexbat/data/be_t1_snapshot/20140411
+ echo /bexbat/data/be_t1_snapshot/20140411
/bexbat/data/be_t1_snapshot/20140411
+ for machine in '$FILERS_LOCATION'
+ dircheck=($(ssh -o "StrictHostKeyChecking no" david#${machine} [[ ! -d "$dir3" ]] \&\& exit 1 \; ls -t1 "$dir3"))
++ ssh -o 'StrictHostKeyChecking no' david#machineP '[[' '!' -d /bexbat/data/be_t1_snapshot/20140411 ']]' '&&' exit 1 ';' ls -t1 /bexbat/data/be_t1_snapshot/20140411
+ [[ 0 != 0 ]]
+ [[ '' = 0 ]]
+ echo 'Everything is Correct'
Everything is Correct
What you want to do is, ls the remote directory (remove the -d flag to ls (which lists only folders), and the head -n1 command as it only prints the first file) and retrieve the data in an array variable.
I also added a check for directory existance [[ -d "$dir3" ]] before executing the ls and escaped the && to not be interpreted on the current bash script.
[[ -d "$dir3" ]] \&\& ls -t1 "$dir3"
To define a bash array, add extra ( ) arround the command., then compare the array size.
dir3="$MAPPED_LOCATION/$FILE_TIMESTAMP" # /bat/testdata/t1_snapshot/20140311
for machine in ${MACHINES[*]}; do
dir3check=($(ssh -o "StrictHostKeyChecking no" david#${machine} [[ -d "$dir3" ]] \&\& ls -t1 "$dir3"))
if [[ "${#dir3check[#]}" -gt 0 ]] ;then
# then do something here
echo "Hello World"
else
# log an error - folder is missing or number of files is zero in server $machine
fi
done
UPDATE:
for machine in ${MACHINES[*]}; do
dircheck=($(ssh -o "StrictHostKeyChecking no" david#${machine} [[ ! -d "$dir3" ]] \&\& exit 1 \; ls -t1 "$dir3"))
#On the ssh command, we exit 1 if the folder doesn't exist. We check the return code with `$?`
if [[ $? != 0 ]] ;then
echo "Folder doesn't exist on $machine";
exit 1
fi
# check number of files retrieved
if [[ "${#dircheck[#]}" = 0 ]] ;then
echo "0 Files on server $machine";
exit 1
fi
#all good for $machine here
done
#all good for all machines here

Resources