Does editing a file while some script is performing grep in it has any effect - linux

Well I am trying to take some decision based on some text is not present in a file, but the problem is the file will be modified while my shell script is doing grep in it.
#!/bin/bash
grep -q "decision" /home/tejto/test/testingshell
ret_code=$?
while [ $ret_code -ne 0 ]
do
echo $ret_code
grep -q "decision" /home/tejto/test/testingshell
echo 'Inside While!'
sleep 5
done
echo 'Gotcha!'
The text "decision" is not present in file while this shell script is started, but when I modify this file by some other bash prompt and put the text 'decision' in it, in this case my script is not taking that change and it is keep on looping in while , so does that mean my shell script caches that particular file ?

Because you are setting ret_code variable only once outside loop and not setting it again inside the loop after next grep -q command.
To fix you will need:
grep -q "decision" /home/tejto/test/testingshell
ret_code=$?
while [ $ret_code -ne 0 ]
do
echo $ret_code
grep -q "decision" /home/tejto/test/testingshell
ret_code=$?
echo 'Inside While!'
sleep 5
done
echo 'Gotcha!'
OR you can shorten your script like this:
#!/bin/bash
while ! grep -q "decision" /home/tejto/test/testingshell
do
echo $?
echo 'Inside While!'
sleep 5
done
echo 'Gotcha!'
i.e. no need to use a variable and directly use grep -q in your while condition.
[EDIT:Tejendra]
#!/bin/bash
until grep -q "decision" /home/tejto/test/testingshell
do
echo $?
echo 'Inside While!'
sleep 5
done
echo 'Gotcha!'
This last solution would not use ret_code and give the desired result as first solution.

Related

Passing variables of bash script to another bash script for submitting job on queue

I tried to read my file, the device (GPU or CPU), and the size of my vector from command line and then with respect to the chosen device, submit my job script with that parameters in to the queue of specific GPU or CPU. But after submitting my job to the queue, when I validate my script like:
bash job.sh
I saw that my parameters file, device, and size from submitjob.sh script did not pass to the job.sh script.
Could you please help me what is my mistake?!
My submitjob.sh:
#!/bin/sh -f
echo "Input The File!";
read file
echo "Choose Gpu Or Cpu!";
read device
echo "Input Vector Size!";
read size
echo
if [ "$device" = "Gpu" ]; then
qsub -I -l nodes=1:gen9:ppn=2 -d . ./job.sh file device size
else
qsub -I -l nodes=1:skl:ppn=2 -d . ./job.sh file device size
fi
my job.sh:
#!/bin/bash
source /opt/intel/inteloneapi/setvars.sh
echo
echo start: $(date "+%y%m%d.%H%M%S.%3N")
echo
$file $device $size
echo
echo stop: $(date "+%y%m%d.%H%M%S.%3N")
echo
You need to to put $ before the variables in submitjob.sh:
qsub -I -l nodes=1:gen9:ppn=2 -d . ./job.sh "$file" "$device" "$size"
Then in job.sh, you get the arguments from $1, $2, etc.
#!/bin/bash
source /opt/intel/inteloneapi/setvars.sh
file=$1
device=$2
size=$3
echo
echo start: $(date "+%y%m%d.%H%M%S.%3N")
echo
"$file" "$device" "$size"
echo
echo stop: $(date "+%y%m%d.%H%M%S.%3N")
echo

Stop grep message from posting

I am working on a script that take 1 string argument and a file. I want it so that if a file is put in that doesn't exist, then it will display the "filename cannot be read" message.
That part does work however it also displays a "grep: grep.txt: No such file or directory" message. Is there any way to stop the grep message from posting and ending the script if the first if statement is true?
#! /bin/sh
if [ ! -f "$2" ]
then
echo "$0" cannot be read 1>&2
fi
if [ $# -eq 2 ]
then
grep "$1" $2
else
echo there is more or less than 2 arguments 1>&2
fi
Exit the script with a non-zero exit code to indicate failure and stop it from continuing on to the grep.
if [ ! -f "$2" ]
then
echo "$0" cannot be read 1>&2
exit 1
fi
You can add /dev/null in grep command it will suppress the error part.
grep "$1" $2 2>/dev/null
The > operator redirects the output usually to a file but it can be to a device. You can also use >> to append.
2> file redirects stderr to file
/dev/null is the null device it takes any input you want and throws it away. It can be used to suppress any output.
You could redirect all errors from grep, for example:
grep "$1" $2 2>/dev/null
(the 2> means redirect standard error, as opposed to standard output with > or 1>).
That introduces a race condition, however: if the file disappears while your script as running, it might still exist when you check that it exists, but be gone by the time grep runs.
You could handle that by checking the exit status...
grep "$1" $2 2>/dev/null
if [[ $? -gt 1 ]]; then
echo "grep failed unexpectedly" >&2
fi
IMHO, in this example it would be better to just let grep print the error.

Linux: Reading the output of readlink /proc/pid/exe within a Bash Script

So I am writing a bash script which will run through all of the process ids in /proc/[pid] and read the executable that was used to run it.
From what I have had a looked at, the /proc filesystem contains the /proc/[pid]/exe symbolic link. Within the bash script I am trying work out how to read the value of "readlink /proc/[pid]/exe" to check if (deleted) or nothing is returned to find out whether the original executable exists on the disk or not.
Is there a way of doing this, so far I have?
#!/bin/bash
pid = "0"
while [ $pid -lt 32769 ]
do
if [-d /proc/$pid]; then
if [-f /proc/$pid/exe]; then
echo $pid
readlink /proc/$pid/exe
fi
fi
pid = $[$pid+1]
done
This fails to work and always returns nothing.I am trying to list all of the processes that no longer have their executables available on disk.
Will this work for you?
#!/bin/bash
for i in $(ls /proc | awk '/^[[:digit:]]+/{print $1}'); do
if [ -h /proc/$i/exe ]; then
echo -n "$i: "
if readlink /proc/$i/exe >/dev/null 2>&1 ; then
echo "executable exists"
else
echo "executable not found"
fi
fi
done
I've updated your script to make it work. Notice that -f checks whether a file name represents a regular file. I would return false for a symbolic link:
pid="0"
while [ $pid -lt 32769 ]
do
if [ -d /proc/$pid ]; then
if [ -h /proc/$pid/exe ]; then
echo $pid
readlink /proc/$pid/exe
fi
fi
pid=$[$pid+1]
done
you can read returned value after any command in shell by printing $? variable:
readlink
echo $?
if link is invalid, $? will be bigger than 0.
however if link exist and actual file is deleted, you can use something like:
ls `readlink somelink`
readlink -f `ls --dereference /proc/$pid/exe`

BASH: redirect for log dillema / duplicate redirection for each loop iteration

I've got a redirect dilemma that I can't get past in a bash backup script I'm developing in CentOS 6.4. I want to redirect all output to two separate files: one tmp and one permanent. The script loops through an external source list and I'd like for the tmp log files to be specific to the source, so that I can send an email if that specific source had errors containing that log (and conversely remove the tmp if the backup completes without error).
I'm using exec to tee my output:
exec > >(tee -a ${templog} /var/log/rob/rob.log) 2>&1
This works if I place at the top of the script, but here the variable isn't defined yet, so I can't do source-specific logs.
If I place this within the while loop, it grabs the variable, but writes a copy of each line determined by the total iterations of the loop; for the example below, I have four sources it iterates through, so I get output for each source in quadruplicate:
-S-07/11/14 09:15:35 ROB-Source Process for cc2-gamma has started-S-
-S-07/11/14 09:15:35 ROB-Source Process for cc2-gamma has started-S-
-S-07/11/14 09:15:35 ROB-Source Process for cc2-gamma has started-S-
-S-07/11/14 09:15:35 ROB-Source Process for cc2-gamma has started-S-
Share cc2-gamma is not Mounted. Try 1 of 5 to mount...
Share cc2-gamma is not Mounted. Try 1 of 5 to mount...
Share cc2-gamma is not Mounted. Try 1 of 5 to mount...
Share cc2-gamma is not Mounted. Try 1 of 5 to mount...
Is there a different way to tee the output within the loop to prevent this (without touching each line of course)? Or is there something rotten in my loops that I'm not seeing? Here's the whole script. Please excuse the mess and style.. I'm clearly not finished. I didn't include the config.conf and backup source file as they don't affect the output. Let me know if needed. Thanks.
#!/bin/bash
#V.2014.0723 - Radation Oncology Backup script
#declarations
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/rob
source /rob/conf/config.conf
while read smbdir 'smbpath' exclfile drive foldername; do
#loop declarations
mountedfile=/rob/${smbdir}.MOUNTED
runningfile=/rob/${smbdir}.RUNNING
lastrunfile=/rob/${smbdir}_${foldername}.LASTRUN
templog=/rob/${smbdir}_${foldername}.TMPLOG
errorfile=/rob/${smbdir}_${foldername}.HAD_ERRORS
backupfile=/rob/${baname:0:3}_rtbackup.sql.bz2 # for the -l seccton below -- sql backup of backup.sql
#exec > >(tee -a ${templog} /var/log/rob/rob.log) 2>&1
### SOURCE BACKUP ##############################################################################################
if [ "$1" == "-s" ]
then
exec > >(tee -a /var/log/rob/rob.log ${templog}) 2>&1
#Write Source STDOUT and STDERR to both permanent and temporary log file. Must be in loop to use variables.
#exec > >(tee -a ${templog} /var/log/rob/rob.log) 2>&1
#exec > >(tee -a /var/log/rob.log ${templog}) 2>
if [ "${sources_active}" == "1" ]
then
echo "-S-$(date "+%m/%d/%y %T") ROB-Source Process for $smbdir has started-S-"
# unmount all cifs shares, due to duplicate mounts, write file to prevent concurrentcy
umount -a -t cifs > /dev/null
# The following will test to see if the souce is mounted, and if not, mount it.
for i in {1..5}
do
if mountpoint -q /mnt/${smbdir}/${drive}/${foldername}
then
echo "Share ${smbdir} is Mounted."
touch $mountedfile
break
else
sleep 2
echo "Share ${smbdir} is not Mounted. Try $i of 5 to mount..."
mkdir -p /mnt/${smbdir}/${drive}/${foldername} > /dev/null
mount -t cifs ${smbpath} -o ro,username=<USER>,password=<PW>,workgroup=<DOMAIN> /mnt/${smbdir}/${drive}/${foldername}
fi
done
# Test to see if above was successful, and if rob is not already running, run the backup.
if [[ -f ${mountedfile}&& ! -f ${runningfile} ]]
then
src="/mnt/${smbdir}/$drive"
dst="/backup/rob/"
touch ${runningfile}
/root/bin/rtbackup -m /mnt -p ${src}/${foldername} -b ${dst} -x #${exclfile}
if [ "$?" -ne "0" ]; then
#Errors Running RTBackup
rm -f ${runningfile} > /dev/null 2>&1
rm -f ${mountedfile}> /dev/null 2>&1
echo "$(date "+%m/%d/%y %T") Source Process for ${smbdir} had errors running:-SSS"
echo "$errors" >&2
touch ${errorfile}
exit 1
else
echo "What the hell is this doing?"
fi
#NO Errors Running RTBACKUP
rm -f ${templog}
rm -f ${runningfile} > /dev/null 2>&1
rm -f ${mountedfile} > /dev/null 2>&1
echo "$(date "+%m/%d/%y %T") Source Process for ${smbdir} did not have any errors"
else
#backup will *NOT* run, cleaning up and logging
rm -f ${mountedfile} > /dev/null 2>&1
echo "$(date "+%m/%d/%y %T") ${smbdir} could not be mounted, or is already in progress. Backup could not complete."
touch ${errorfile}
tail /var/log/rob/robso.log | mail -s "ROBSO Failed to run for ${smbdir} on ${baname}" ${email}
fi
echo "-F-$(date "+%m/%d/%y %T") ROB-Source Process for ${smbdir} has finished-F-"
#break
elif [[ "${sources_active}" == "0" ]]
then
echo "***$(date "+%m/%d/%y %T") ROB-Source Process for ${smbdir} did not run because the job is not set as active***"
#break
fi
done < /rob/conf/${baname}.conf
if [ $? -eq 10 ]; then exit 0; fi
You can use curly braces to redirect a set of commands; as it says in the bash manual about command grouping, "When commands are grouped, redirections may be applied to the entire command list". It behaves more-or-less like an anonymous function.
{
command1
command2
} > >(tee -a ${templog} /var/log/rob/rob.log) 2>&1
You can do the same with a named function, too, if you're so inclined, but I don't know offhand what environment would be used to expand the redirections. (If you do, please edit this answer!)
# Untested. This MIGHT work.
your_log_command() {
command1
command2
} > >(tee -a $1 /var/log/rob/rob.log) 2>&1
your_log_command $templog
your_log_command $something_else

Bash Script : Unwanted Output

I have this simple bash script:
I run ns simulator on each file passed in argument where last argument is some text string to search for.
#!/bin/bash
nsloc="/home/ashish/ns-allinone-2.35/ns-2.35/ns"
temp="temp12345ashish.temp"
j=1
for file in "$#"
do
if [ $j -lt $# ]
then
let j=$j+1
`$nsloc $file > $temp 2>&1`
if grep -l ${BASH_ARGV[0]} $temp
then
echo "$file Successful"
fi
fi
done
I expected:
file1.tcl Successful
I am getting:
temp12345ashish.temp
file1.tcl Successful
When i run the simulator command myself on the terminal i do not get the file name to which output is directed.
I am not getting from where this first line of output is getting printed.
Please explain it.
Thanks in advance.
See man grep, and see specifically the explanation of the -l option.
In your script (above), you are using -l, so grep is telling you (as instructed) the filename where the match occurred.
If you don't want to see the filename, don't use -l, or use -q with it also. Eg:
grep -ql ${BASH_ARGV[0]} $temp
Just silence the grep:
if grep -l ${BASH_ARGV[0]} $temp &> /dev/null

Resources