my bash script wont run, and does not output anything past echo "Running gke old user cleanup". There is no fail message, it just doesn't run. Any suggestions?
#!/bin/bash
set -o pipefail
set -o nounset
date
echo "Running old user cleanup"
for user in $(awk -F':' '$1 ~ /^kub-[a-z0-9]{20}$/ { print $1 }' /etc/passwd); do
echo "Cleaning up '${user}'"
userdel -r "${user}"
rc=$?
if [[ $rc != 0 ]]; then
echo "Failed to cleanup '${user}': exit code: ${rc}"
else
echo "Successfully cleaned up '${user}'"
fi
done
Maybe simplify the loop.
while read user
do if userdel -r "${user}"
then echo "Successfully cleaned up '${user}'"
else echo "Failed to cleanup '${user}': exit code: '$?'"
fi
done < <( awk -F':' '$1 ~ /^gke-[a-z0-9]{20}$/ { print $1 }' /etc/passwd )
Should at least be easier to debug.
Add set -x as suggested to see what's being evaluated.
Related
I'm trying to do a script that does things on my linux computer but does not respects wait commands.
That's my code that does not work
cat file.txt | while read line || [[ -n $line ]]; do
do
QUEST="$(./fi $line | grep -oE " fi " &> A.txt; echo $? >"$dir")" & proc=$!
wait "$proc"
read ret <"$dir"
if [[ "$QUEST" != "" ]];then echo "$line" &>> A.txt; fi; unset QUEST;
done &> /dev/null & wait
It have to do one quest a time and save the output (that could exists or not).
When you run a command in the background, it's run in a subshell. Any variable assignments are not visible in the original shell, so the assignment to QUEST doesn't work.
You don't need to do that in the background, since you're immediately waiting for the command to finish. Just run it normally.
while read line || [[ -n $line ]]; do
do
QUEST="$(./fi $line | grep -oE " fi " &> A.txt)"
ret=$?
if [[ "$QUEST" != "" ]]
then echo "$line" &>> A.txt
fi
done &> /dev/null < file.txt
unset QUEST
There's also no need to write $? to $dir. The exit status of a variable assignment from a command substitution is the exit status of the command.
I'm trying to create a script to check if user accounts have valid home directories.
This is what i got at the moment:
#!/bin/bash
cat /etc/passwd | awk -F: '{print $1 " " $3 " " $6 }' | while read user userid directory; do
if [ $userid -ge 1000 ] && [ ! -d "$directory ]; then
echo ${user}
fi
done
This works. I get the expected output which is the username of the account with an invalid home directory.
eg. output
student1
student2
However, I am unable to make it so that ONLY if there is no issues with the valid home directories and all of them are valid, echo "All home directories are valid".
Didn't run it, but it should be something like:
#!/bin/bash
users=()
cat /etc/passwd | awk -F: '{print $1 " " $3 " " $6 }' | while read user userid directory; do
if [ $userid -ge 1000 ] && [ ! -d "$directory" ]; then
users=+("${user}")
fi
done
if test -n ${#users[#]} == 0; then
echo "All home directories are valid"
else
for (( i=0; i<${#users[#]}; i++ )); do echo "${users[$i]}" ; done
fi
You could set a flag, and unset it if you see an invalid directory. Or you could simply check whether your loop printed anything.
You have a number of common antipatterns which you'll want to avoid, too.
# Avoid useless use of cat
# If you are using Awk anyway,
# use it for user id comparison, too
awk -F: '$3 >= 1000 {print $1, $6 }' /etc/passwd |
# Basically always use read -r
while read -r user directory; do
# Fix missing close quote
if [ ! -d "$directory" ]; then
# Quote user
echo "$user"
fi
done |
# If no output, print default message
grep '^' >&2 || echo "No invalid directories" >&2
A proper tool prints its diagnostic output to standard error, not standard output, so I added >&2 to the end.
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.
I am trying to write a small bash script to monitor the output of RiotShield (a 3rd party player scraper for League of Legends) for crashes. If a keyword is found in the log it should kill the process and restart it.
Here is my bash script as is:
#!/bin/bash
crash[1]="disconnected"
crash[2]="38290209"
while true; do
list=$(tail log.log)
#clear
echo "Reading Log"
echo "========================================"
echo $list
for item in ${list//\\n/ }
do
for index in 1 2
do
c=${crash[index]}
#echo "Crash Word:" $c
if [[ "$c" == *"$item"* ]]; then
echo "RiotShield has crashed."
echo "Killing RiotShield."
kill $(ps aux | grep '[R]iotShield.exe' | awk '{print $2}')
echo "RiotShield killed!"
echo "Clearing log."
echo > log.log
echo "Starting RiotShield"
(mono RiotShield.exe >> log.log &)
fi
done
done
sleep 10
done
My crash array are keywords that I know show in the log when it crashes. I have 38290209 in there only for testing purposes as it is my summoner ID on League of Legends and the moment I preform a search for my Summoner name the ID shows in the log.
The problem is even when disconnected and 38290209 do not show up in the log my
if [[ "$c" == *"$item"* ]]; then
fires, kills the RiotShield process and then relaunches it.
The length of the crash array will grow as I find more keywords for crashes so I cant just do
if [[ "$c" == "*disconnected*" ]]; then
Please and thanks SOF
EDIT:
Adding working code:
#!/bin/bash
crash[1]="disconnected"
crash[2]="error"
while true; do
list=$(tail log.log)
clear
echo "Reading Log"
echo "========================================"
echo $list
for index in 1 2
do
c=${crash[index]}
#echo "Crash Word:" $c
if [[ $list == *$c* ]]; then
echo "RiotShield has crashed."
echo "Crash Flag: " $c
echo "Killing RiotShield."
kill $(ps aux | grep '[R]iotShield.exe' | awk '{print $2}')
echo "RiotShield killed!"
echo "Clearing log."
echo > log.log
echo "Starting RiotShield"
(mono RiotShield.exe >> log.log &)
fi
done
sleep 10
done
I think you have the operands in your expression the wrong way around. It should be:
if [[ $item == *$c* ]]; then
because you want to see if a keyword ($c) is present in the line ($item).
Also, I'm not sure why you need to break the line into items by doing this: ${list//\\n/ }. You can just match the whole line.
Also note that double-quotes are not required within [[.
I am trying to nest multiple if-statements as the following:
#!/bin/bash
# start_server.sh
#
# Use this script to start the MarketDataTransmitter.
#
# Usage: ./start_server.sh Starts the MarketDataTransmitter.
reset=$(tput sgr0)
red=$(tput setaf 1)
green=$(tput setaf 2)
yellow=$(tput setaf 3)
cyan=$(tput setaf 6)
echo
directory=$(ls -l)
check_exist=$(awk -v a="$directory" -v b="MarketDataTransmitter" 'BEGIN { print index(a, b) }')
if [ "$check_exist" = "0" ]; then
# MarketDataTransmitter is not present.
echo "${red}[ERROR]${reset} Could not start ${yellow}MarketDataTransmitter${reset}."
echo " ${yellow}MarketDataTransmitter${reset} could not be found."
else
# MarketDataTransmitter is present.
processes=$(ps -ef | grep -i "MarketDataTransmitter" | grep -v "grep" | grep -v "bash" | awk '{ print $8 }')
check_run=$(awk -v a="$processes" -v b="MarketDataTransmitter" 'BEGIN { print index(a, b) }')
if [ "$check_run" = "0" ]; then
# MarketDataTransmitter is not running.
if [ -e "srv.log" ]; then
if [ -s "srv.log" ]; then
if [ -d "logs" ]; then
date_time=$(date '+%Y%m%d_%H_%M_%S')
new_log_name="srv_$date_time.log"
mv srv.log $new_log_name
mv $new_log_name logs
else
mkdir logs
date_time=$(date '+%Y%m%d_%H_%M_%S')
new_log_name="srv_$date_time.log"
mv srv.log $new_log_name
mv $new_log_name logs
fi
else
echo "srv.log is empty and will be removed."
rm -rf srv.log
fi
else
# No srv.log but this is to start MarketDataTransmitter so we can ignore.
fi
./MarketDataTransmitter > srv.log &
echo "${yellow}MarketDataTransmitter${reset} has been started."
else
# MarketDataTransmitter is already running.
echo "${red}[ERROR]${reset} Could not start ${yellow}MarketDataTransmitter${reset}."
echo " ${yellow}MarketDataTransmitter${reset} is already running."
fi
fi
echo
However it is giving me syntax complaints saying:
syntax error near unexpected token `fi'
on the very last 'fi'
Does anyone know why?
Thanks.
[EDIT] Full code has been posted.
You have an else statement and fi statement with nothing between them on lines 44-46 (just a comment between them). In bash, you need to have some statement in the body of that else block, or take the else block out.