Getting "No such file or directory" even after using > /dev/null 2>&1 at the end of the command - linux

I have written a script where it checks the PID of that JVM. If PID is not existing for that specific JVM, it will give exit status 2 and terminates the script. To check the PID, I do a cat of specific file which contains the PID. When there is no PID or no file which contains PID, it is throwing "No such file or directory" even after redirecting the output using > /dev/null 2>&1 at the end of the command.
I don't want the output displayed on the screen. If someone could help me on that would be really helpful.
EDIT this is the code snippet:
ONLINE=grep -ir "$HOSTNAME-"$VAR" is currently online" /home/logs/$GF_OWNER/$HOSTNAME-"$VAR"/$HOSTNAME-"$VAR".log | wc -l
OFFLINE=0
PID=cat /home/logs/$GF_OWNER/$HOSTNAME-"$VAR"/gemstart.pid

It think you should try to test if your file exists before using cat/ls/whatever on it. For that, use the if/test structure :
if [ -e $PETH_TO_THE_FILE ]; then
//processing here
else
fi
This way you won't have unnecessary output.

Related

Running a process with the TTY detached

I'd like to run a linux console command from a terminal, preventing it from accessing the TTY by itself (which will, for example, happen often when the console command tries to request a password from the user - this should just fail). The closest I get to a solution is using this wrapper:
temp=`mktemp -d`
echo "$#" > $temp/run.sh
mkfifo $temp/out $temp/err
setsid sh -c "sh $temp/run.sh > $temp/out 2> $temp/err" &
cat $temp/err 1>&2 &
cat $temp/out
rm -f $temp/out $temp/err $temp/run.sh
rmdir $temp
This runs the command as expected without TTY access, but passing the stdout/stderr output through the FIFO pipes does not work for some reason. I end up with no output at all even though the process wrote to stdout or stderr.
Any ideas?
Well, thank you all for having a look. Turns out that the script already contained a working approach. It just contained a typo which caused it to fail. I corrected it in the question so it may serve for future reference.

What does ps actually return? (Different value depending on how it is called)

I have a script containing this snippet:
#!/bin/bash
set +e
if [ -O "myprog.pid" ]; then
PID=`/bin/cat myprog.pid`
if /bin/ps -p ${PID}; then
echo "Already running" >> myprog.log
exit 0
else
echo "Old pidfile found" >> myprog.log
fi
else
echo "No pidfile found" >> myprog.log
fi
echo $$ > myprog.pid
This file is called by a watchdog script, callmyprog, which looks like this:
#!/bin/bash
myprog &
It seems to be a problem with if /bin/ps -p ${PID}. The problem manifests itself in this way. If I manually call myprog when it is running I get the message "Already running" as it should. Same thing happens when I manually run the script callmyprog. But when the watchdog runs it, I instead get "Old pidfile found".
I have checked the output from ps and in all cases it finds the process. When I'm calling myprog manually - either directly or through callmyprog, I get the return code 0, but when the watchdog calls it I get the return code 1. I have added debug printouts to the above snippets to print basically everything, but I really cannot see what the problem is. In all cases it looks something like this in the log when the ps command is run from the script:
$ ps -p 1
PID TTY TIME CMD
1 ? 01:06:36 systemd
The only difference is that the return value is different. I checked the exit code with code like this:
/bin/ps -p ${PID}
echo $? >> myprog.log
What could possibly be the cause here? Why does the return code vary depending on how I call the script? I tried to download the source code for ps but it was to complicated for me to understand.
I was able to "solve" the problem with an ugly hack. I piped ps -p $PID | wc -l and checked that the number of lines were at least 2, but that feels like an ugly hack and I really want to understand what the problem is here.
Answer to comment below:
The original script contains absolute paths so it's not a directory problem. There is no alias for ps. which ps yields /bin/ps. The scripts are run as root, so I cannot see how it can be a permission problem.

Redirect all output in a bash script when using set -x, capture pid and all output

I'm modifying an old script and for some reason it uses a subshell. I'm not sure if maybe the subshell is what's tripping me up. What I really want is to start a service and capture all of STDOUT and STDERR to a file as well as it's PID. Additionally, however I want some debug information in the log file. Consider the script below (startFoo.sh):
#!/bin/bash
VARIABLE=$(something_dynamic)
echo "Some output"
(
# Enable debugging
set -x
foo -argument1=bar \
-argument2=$VARIABLE
# Disable debugging
set +x
) > /tmp/foo_service.log 2>&1 &
OUTER_PID=$!
echo $OUTER_PID > foo.pid
This seems to work in that I'm capturing most of the output to the log as well as the PID, but for some reason not all of the output is redirected. When I run the script, I see this in my terminal:
[me#home ~]$ sudo startFoo.sh
Some output
[me#home ~]$ + foo -argument1=bar -argument2=value
How can I squash the output in my prompt that says [me#home ~]$ + foo...?
Note, this question may be related to another question: redirect all output in a bash script when using set -x, however my specific usage is different.
UPDATE: My script now looks like this, but something is still not quite right:
#!/bin/bash
VARIABLE=$(something_dynamic)
echo "Some output"
(
# Enable debugging
set -x
foo -argument1=bar \
-argument2=$VARIABLE
# Disable debugging
set +x
) > /tmp/foo_service.log 2>&1 &
PID=$!
echo $PID > foo.pid
However, when I do this, the PID file contains the PID for startFoo.sh, not the actual invocation of foo which is what I really want to capture and be able to kill. Ideally I could kill both startFoo.sh and foo with one PID, but I'm not sure how to do that. How is this normally handled?
UPDATE: The solution (thanks to a conversation with #konsolebox) is below:
#!/bin/bash
VARIABLE=$(something_dynamic)
echo "Some output"
{
# Enable debugging
set -x
foo -argument1=bar \
-argument2="$VARIABLE" &
PID=$!
echo $PID > foo.pid
# Disable debugging
set +x
} > /tmp/foo_service.log 2>&1
Change 2>&1> /tmp/foo_service.log to >/tmp/foo_service.log 2>&1.
You should first redirect fd 1 to the file, then let fd 2 duplicate it. What you're doing on the former is that you first redirect fd 2 to 1 which only copies the default stdout, not the file's fd which is opened after it.

Notify via email if something wrong got happened in the shell script

fileexist=0
mv /data/Finished-HADOOP_EXPORT_&Date#.done /data/clv/daily/archieve-wip/
fileexist=1
--some other script below
Above is the shell script I have in which in the for loop, I am moving some files. I want to notify myself via email if something wrong got happened in the moving process, as I am running this script on the Hadoop Cluster, so it might be possible that cluster went down while this was running etc etc. So how can I have better error handling mechanism in this shell script? Any thoughts?
Well, atleast you need to know "What are you expecting to go wrong". based on that you can do this
mv ..... 2> err.log
if [ $? -ne 0 ]
then
cat ./err.log | mailx -s "Error report" admin#abc.com
rm ./err.log
fi
Or as William Pursell suggested, use-
trap 'rm -f err.log' 0; mv ... 2> err.log || < err.log mailx ...
mv may return a non-zero return code upon error, and $? returns that error code. If the entire server goes down then unfortunately this script doesn't run either so that's better left to more advanced monitoring tools such as Foglight running on a different monitoring server. For more basic checks, you can use method above.

Redirecting Output of Bash Child Scripts

I have a basic script that outputs various status messages. e.g.
~$ ./myscript.sh
0 of 100
1 of 100
2 of 100
...
I wanted to wrap this in a parent script, in order to run a sequence of child-scripts and send an email upon overall completion, e.g. topscript.sh
#!/bin/bash
START=$(date +%s)
/usr/local/bin/myscript.sh
/usr/local/bin/otherscript.sh
/usr/local/bin/anotherscript.sh
RET=$?
END=$(date +%s)
echo -e "Subject:Task Complete\nBegan on $START and finished at $END and exited with status $RET.\n" | sendmail -v group#mydomain.com
I'm running this like:
~$ topscript.sh >/var/log/topscript.log 2>&1
However, when I run tail -f /var/log/topscript.log to inspect the log I see nothing, even though running top shows myscript.sh is currently being executed, and therefore, presumably outputting status messages.
Why isn't the stdout/stderr from the child scripts being captured in the parent's log? How do I fix this?
EDIT: I'm also running these on a remote machine, connected via ssh using pseudo-tty allocation, e.g. ssh -t user#host. Could the pseudo-tty be interfering?
I just tried your the following: I have three files t1.sh, t2.sh, and t3.sh all with the following content:
#!/bin/bash
for((i=0;i<10;i++)) ; do
echo $i of 9
sleep 1
done
And a script called myscript.sh with the following content:
#!/bin/bash
./t1.sh
./t2.sh
./t3.sh
echo "All Done"
When I run ./myscript.sh > topscript.log 2>&1 and then in another terminal run tail -f topscript.log I see the lines being output just fine in the log file.
Perhaps the things being run in your subscripts use a large output buffer? I know when I've run python scripts before, it has a pretty big output buffer so you don't see any output for a while. Do you actually see the entire output in the email that gets sent out at the end of topscript.sh? Is it just that while the processes run you're not seeing the output?
try
unbuffer topscript.sh >/var/log/topscript.log 2>&1
Note that unbuffer is not always available as a std binary in old-style Unix platforms and may require a search and installation for a package to support it.
I hope this helps.

Resources