Hi I have a shell script that inserts disk status of linux servers in SQL server. Before inserting the SQL command, the program executes and ends properly. However, when I inserted the SQL command, the .sh file never goes to the next line to execute. It is always in a loop. Kindly help
#!/bin/bash
#Functions here
insert() {
echo "--INSERT FUNCTION--"
echo "$1"
fsname=$1
fs=$(echo "${fsname: -3}")
sqlcmd -S <ipadd> -U <user> -P <pass> -d tech_admin -Q "EXEC insertDiskStatus $fs"
sleep 1
}
echo "TEST"
cd ~/Documents
pwd
df -Ph --exclude-type=tmpfs --exclude-type=ext3 --block-size=GB | column -t | sed 1d > diskspace.log
filename=diskspace.log
while read -r line
do
this=$line
fs=$(echo $line | awk '{print $1}')
insert $fs
done < "$filename"
I had the same problem. In my bash script, I have sqlcmd in a while loop and the loop would continue running the first item in the list over and over and not continue on to the next item. As mentioned in the comments, adding this < /dev/null to the end of sqlcmd line will cause it to get out of stuck spot in the loop and carry on to the next tiem.
Related
I am trying to grep some info from a directory for each line in a file. I am using while loop to grep each line of a file. The grep alone works perfectly. I tested my while loop with echo and it works perfectly but when I use grep inside it gives me no output.
while IFS= read -r LINE; do
grep --include=\requests-definition.const.ts -rnwH $DIR -e "$LINE";
echo $LINE;
done < key_list
my key_list is a text file having a key on each line.
when I use the grep alone it works but it may not work In a while loop.
Thanks !
Make sure you loop is not exiting at the first Line without match.
From grep Man
EXIT STATUS
Normally the exit status is 0 if a line is selected, 1 if no lines were selected, and 2 if
an error occurred. However, if the -q or --quiet or --silent is used and a line is
selected, the exit status is 0 even if an error occurred.
To aviod exiting you have several ways to go:
Use a subshell with $(grep ...)
use the flag set +e
while IFS= read -r LINE; do
set +x # don't exit if exit code is different from 0
grep --include=\requests-definition.const.ts -rnwH $DIR -e "$LINE";
set -e # exit if exit code is different from 0
echo $LINE;
done < key_list
the problem was solved by removing special characters from key_list using dos2unix command.
I've placed a bash file inside .zshrc and tried all different ways to run it every time I open a new terminal window or source .zshrc but no luck.
FYI: it was working fine on .bashrc
here is .zshrc script:
#Check if ampps is running
bash ~/ampps_runner.sh & disown
Different approach:
#Check if ampps is running
sh ~/ampps_runner.sh & disown
Another approach:
#Check if ampps is running
% ~/ampps_runner.sh & disown
All the above approaches didn't work (meaning it supposes to run an app named ampps but it doesn't in zsh.
Note: It was working fine before switching to zsh from bash. so it does not have permission or syntax problems.
Update: content of ampps_runner.sh
#! /usr/bin/env
echo "########################"
echo "Checking for ampps server to be running:"
check=$(pgrep -f "/usr/local/ampps" )
#[ -z "$check" ] && echo "Empty: Yes" || echo "Empty: No"
if [ -z "$check" ]; then
echo "It's not running!"
cd /usr/local/ampps
echo password | sudo -S ./Ampps
else
echo "It's running ..."
fi
(1) I believe ~/.ampps_runner.sh is a bash script, so, its first line should be
#!/bin/bash
or
#!/usr/bin/bash
not
#! /usr/bin/env
(2) Then, the call in zsh script (~/.zshrc) should be:
~/ampps_runner.sh
(3) Note: ~/.ampps_runner.sh should be executable. Change it to executable:
$ chmod +x ~/ampps_runner.sh
The easiest way to run bash temporarily from a zsh terminal is to
exec bash
or just
bash
Then you can run commands you previously could only run in bash. An example
help exec
To exit
exit
Now you are back in your original shell
If you want to know your default shell
echo $SHELL
or
set | grep SHELL=
If you want to reliably know your current shell
ps -p $$
Or if you want just the shell name you might use
ps -p $$ | awk "NR==2" | awk '{ print $4 }' | tr -d '-'
And you might just put that last one in a function for later, just know that it is only available if it was sourced in a current shell.
whichShell(){
local defaultShell=$(echo $SHELL | tr -d '/bin/')
echo "Default: $defaultShell"
local currentShell=$(ps -p $$ | awk "NR==2" | awk '{ print $4 }' | tr -d '-')
echo "Current: $currentShell"
}
Call the method to see your results
whichShell
If I call a script this way:
myScript.sh -a something -b anotherSomething
Within my script is there a way to get the command that called the script?
In my script on the first line I'm trying to use:
lastCommand=!!
echo $lastCommand
But the result is always null.
If I do echo !! the only thing that prints to the console is !!, but from the command line if I do echo !! I get the last command printed.
I've also tried:
echo $BASH_COMMAND
but I'm getting null here as well. Is it because the script is called in a subshell and thus there is no previous command stored in memory for the subshell?
The full command which called the script would be "$0" "$#", that is, the command itself followed by all the arguments quoted. This may not be the exact command which was run, but if the script is idempotent it can be run to get the same result:
$ cat myScript.sh
#!/usr/bin/env bash
printf '%q ' "$0" "$#"
printf '\n'
$ ./myScript.sh -a "foo bar" -b bar
./myScript.sh -a foo\ bar -b bar
Here's my script myScript.sh
#!/bin/bash
temp=`mktemp`
ps --pid $BASHPID -f > $temp
lastCommand=`tail -n 1 $temp | xargs | cut -d ' ' -f 8-`
rm $temp
echo $lastCommand
or
#!/bin/sh
last=`cat /proc/$$/cmdline | xargs -0`
echo $last
There are other threads with this same topic but my issue is unique. I am running a bash script that has a function that sshes to a remote server and runs a sudo command on the remote server. I'm using the ssh -t option to avoid the requiretty issue. The offending line of code works fine as long as it's NOT being called from within the while loop. The while loop basically reads from a csv file on the local server and calls the checkAuthType function:
while read inputline
do
ARRAY=(`echo $inputline | tr ',' ' '`)
HOSTNAME=${ARRAY[0]}
OS_TYPE=${ARRAY[1]}
checkAuthType $HOSTNAME $OS_TYPE
<more irrelevant code>
done < configfile.csv
This is the function that sits at the top of the script (outside of any while loops):
function checkAuthType()
{
if [ $2 == linux ]; then
LINE=`ssh -t $1 'sudo grep "PasswordAuthentication" /etc/ssh/sshd_config | grep -v "yes\|Yes\|#"'`
fi
if [ $2 == unix ]; then
LINE=`ssh -n $1 'grep "PasswordAuthentication" /usr/local/etc/sshd_config | grep -v "yes\|Yes\|#"'`
fi
<more irrelevant code>
}
So, the offending line is the line that has the sudo command within the function. I can change the command to something simple like "sudo ls -l" and I will still get the "stdin is not a terminal" error. I've also tried "ssh -t -t" but to no avail. But if I call the checkAuthType function from outside of the while loop, it works fine. What is it about the while loop that changes the terminal and how do I fix it? Thank you one thousand times in advance.
Another option to try to get around the problem would be to redirect the file to a different file descriptor and force read to read from it instead.
while read inputline <&3
do
ARRAY=(`echo $inputline | tr ',' ' '`)
HOSTNAME=${ARRAY[0]}
OS_TYPE=${ARRAY[1]}
checkAuthType $HOSTNAME $OS_TYPE
<more irrelevant code>
done 3< configfile.csv
I am guessing you are testing with linux. You should try add the -n flag to your (linux) ssh command to avoid having ssh read from stdin - as it normally reads from stdin the while loop is feeding it your csv.
UPDATE
You should (usually) use the -n flag when scripting with SSH, and the flag is typically needed for 'expected behavior' when using a while read-loop. It does not seem to be the main issue here, though.
There are probably other solutions to this, but you could try adding another -t flag to force pseudo-tty allocation when stdin is not a terminal:
ssh -n -t -t
BroSlow's approach with a different file descriptor seems to work! Since the read command reads from fd 3 and not stdin,
ssh and hence sudo still have or get a tty/pty as stdin.
# simple test case
while read line <&3; do
sudo -k
echo "$line"
ssh -t localhost 'sudo ls -ld /'
done 3<&- 3< <(echo 1; sleep 3; echo 2; sleep 3)
I'm trying to get the output of the ps command to output to a file, then to use that file to populate a radiolist. So far I'm having problems.
eval "ps -o pid,command">/tmp/process$$
more /tmp/process$$
sed -e '1d' /tmp/process$$ > /tmp/process2$$
while IFS= read -r pid command
do
msgboxlist="$msgboxlist" $($pid) $($command) "off"
done</tmp/process2$$
height=`wc -l "/tmp/process$$" | awk '{print $1}'`
width=`wc --max-line-length "/tmp/process$$" | awk '{print $1}'`
echo $height $width
dialog \
--title "Directory Listing" \
--radiolist "Select process to terminate" "$msgboxlist" $(($height+7)) $(($width+4))
So far not only does the while read not split the columns into 2 variables ($pid is the whole line and $command is blank) but when I try to run this the script is trying to run the line as a command. For example:
+ read -r pid command
++ 7934 bash -x assessment.ba
assessment.ba: line 322: 7934: command not found
+ msgboxlist=
+ off
assessment.ba: line 322: off: command not found
Basically I have no idea where I'm supposed to be putting quotes, double quotes and backslashes. It's driving me wild.
tl;dr Saving a command into a variable without running it, how?
You're trying to execute $pid and $command as commands:
msgboxlist="$msgboxlist" $($pid) $($command) "off"
Try:
msgboxlist="$msgboxlist $pid $command off"
Or use an array:
msgboxlist=() # do this before the while loop
msgboxlist+=($pid $command "off")
# when you need to use the whole list:
echo "${msgboxlist[#]}"
Your script can be refactored by removing some unnecessary calls like this:
ps -o pid=,command= > /tmp/process$$
msgboxlist=""
while read -r pid command
do
msgboxlist="$msgboxlist $pid $command off"
done < /tmp/process2$$
height=$(awk 'END {print NR}' "/tmp/process$$")
width=$(awk '{if (l<length($0)) l=length($0)} END{print l}' "/tmp/process$$")
dialog --title "Directory Listing" \
--radiolist "Select process to terminate" "$msgboxlist" $(($height+7)) $(($width+4))
I have to admit, I'm not 100% clear on what you're doing; but I think you want to change this:
msgboxlist="$msgboxlist" $($pid) $($command) "off"
to this:
msgboxlist+=("$pid" "$command" off)
which will add the PID, the command, and "off" as three new elements to the array named msgboxlist. You'd then change "$msgboxlist" to "${msgboxlist[#]}" in the dialog command, to include all of those elements as arguments to the command.
Use double quotes when you want variables to be expanded. Use single quotes to disable variable expansion.
Here's an example of a command saved for later execution.
file="readme.txt"
cmd="ls $file" # $file is expanded to readme.txt
echo "$cmd" # ls readme.txt
$cmd # lists readme.txt
Edit adressing the read:
Using read generally reads an entire line. Consider this instead (tested):
ps o pid=,command= | while read line ; do
set $line
pid=$1
command=$2
echo $pid $command
done
Also note the different usage of 'ps o pid=,command=' to skip displaying headers.