A Running Bash Script Is Hung Somewhere. How to Find Out What Line It Is On

Howto debug running bash script

Try to find the process id (pid) of the shell, you may use ps -ef | grep <script_name>
Let's set this pid in the shell variable $PID.
Find all the child processes of this $PID by:

ps --ppid $PID

You might find one or more (if for example it's stuck in a pipelined series of commands). Repeat this command couple of times. If it doesn't change this means the script is stuck in certain command. In this case, you may attach trace command to the running child process:

sudo strace -p $PID

This will show you what is being executed, either indefinite loop (like reading from a pipe) or waiting on some event that never happens.

In case you find ps --ppid $PID changes, this indicates that your script is advancing but it's stuck somewhere, e.g. local loop in the script. From the changing commands, it can give you a hint where in the script it's looping.

Bash Script hangs when run in go program

Here's from the docs for Cmd.wait with emphasis:

func (c *Cmd) Wait() error

Wait waits for the command to exit and waits for any copying to stdin or copying from stdout or stderr to complete.

This means that it will wait for all processes to close the relevant pipe, not just for the given process to exit. This is a problem when you start processes in the background:

Here's an example:

#!/bin/bash
sleep 3600 &
echo "Exit"

sleep inherits stdin/out/err and keeps them open for an hour. It will exit immediately in a terminal because Bash doesn't and can't care what has the terminal open:

$ ./testscript; echo "Returned"
Exit
Returned
$

However, if you pipe to cat, it will wait for all potential data to finish (in case sleep decides to write something later), and bash in turns waits on cat:

$ ./testscript | cat; echo "Returned"
Exit
(Hangs for an hour)

You can fix this by making sure any forked processes won't be writing to the pipe by redirecting somewhere else:

#!/bin/bash
sleep 3600 < /dev/null > /dev/null 2>&1 &
echo "Exit"

Since sleep no longer holds the pipe open, it returns immediately, both in the shell and with Cmd.Wait():

$ ./testscript | cat; echo "Returned"
Exit
Returned

Shell script to check whether a server is reachable?

You can use ping -c4 $ip_address where $ip_address is the ip of your remote server and parse the output to capture the successful packets and/or failed packets and use mail -s to send the log via email.

Here is something to get you started and you can build on it.

ping -c4 www.google.com | awk '/---/,0'

This will give an output like this -

[jaypal:~/Temp] ping -c4 www.google.com | awk '/---/,0'
--- www.l.google.com ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 36.638/36.870/37.159/0.196 ms

I checked the Solaris man-page for ping. Output from ping on Solaris box is different. Also, on Linux you limit the packets by stating -c and number of packets. On Solaris you would have to do -

ping -s www.google.com 2 4

/usr/sbin/ping -s [-l | -U] [-adlLnrRv] [-A addr_family]
[-c traffic_class] [-g gateway [ -g gateway...]] [-
F flow_label] [-I interval] [-i interface] [-P tos] [-
p port] [-t ttl] host [data_size] [npackets]
^ ^
| |
---------------------------------------

Unfortunately I don't have a solaris box handy to help you out with.

Bash - back tick invocation blocks for ever

if the call to callee.sh is hanging with parameters, try executing it outside the script with parameters and check if it is hanging there as well...
Anyways, the best way of saving output (and printing it out afterwards):

result="$(./callee.sh param1 param2 param2)"
echo "${result}" <--- this should show the line breaks

How to find all files containing specific text (string) on Linux?

Do the following:

grep -rnw '/path/to/somewhere/' -e 'pattern'
  • -r or -R is recursive,
  • -n is line number, and
  • -w stands for match the whole word.
  • -l (lower-case L) can be added to just give the file name of matching files.
  • -e is the pattern used during the search

Along with these, --exclude, --include, --exclude-dir flags could be used for efficient searching:

  • This will only search through those files which have .c or .h extensions:

    grep --include=\*.{c,h} -rnw '/path/to/somewhere/' -e "pattern"
  • This will exclude searching all the files ending with .o extension:

    grep --exclude=\*.o -rnw '/path/to/somewhere/' -e "pattern"
  • For directories it's possible to exclude one or more directories using the --exclude-dir parameter. For example, this will exclude the dirs dir1/, dir2/ and all of them matching *.dst/:

    grep --exclude-dir={dir1,dir2,*.dst} -rnw '/path/to/search/' -e "pattern"

This works very well for me, to achieve almost the same purpose like yours.

For more options, see man grep.



Related Topics



Leave a reply



Submit