2

I have a written a shell script that helps me calculate the disk utilization in remote servers using df -h. I'm including the code snippet below

s_arch_1_per=`sshpass -p 'password' ssh root@server_ip_1 "df -h | grep '/Archive_1'| awk '{print $ (NF-1)}'"`

master_per=sshpass -p 'password' ssh nidhal@server_ip_2 "df -h | grep '/dev/mapper/centos-root'| awk '{print $ (NF-1)}'"

arch_5_per=df -h | grep '/archive_1'| awk '{print $ (NF-1)}'

The problem is either in the local or remote system the execution of df -h sometimes hangs due to corrupt mount points thus preventing my entire shell from executing completely. How do I prevent my script from getting stuck on a line when df -h doesn't work in one of the systems? I want my script to skip a line and continue to the next line if that line is taking too long to get executed.

  • You can use timeout or something similar, but that assumes the process is not stuck in uninterruptable sleep. When your df gets stuck, does it respond to SIGKILL? – forest May 10 '22 at 03:57
  • It doesn't respond to Ctrl C – nidooooz May 10 '22 at 04:38
  • 1
    nothing to add to @cas's answer, and not directly related to NFS's hang problem, yet don't pipe grep to awk, use awk '/archive1/ { print $(NF-1)}' as awk can grep fixed string. – Archemar May 10 '22 at 05:14
  • 1
    not an answer, but important: instead of having a clear-text password, you should: create a pair of private/public keys, and then put the public-key (at the right format) inside the destinations' "~remoteuser/.ssh/authorized_keys" file (with mode 600 or 400, ie not readable by everyone), and then you should be able, using the right private key (if you didn't recreate the one by default) access the destinations without any password. Protect the private key at all costs (only the user launching the operations should ever be able to read it) – Olivier Dulac May 10 '22 at 12:42

1 Answers1

6

Instead of piping df's output into grep (which causes df to query all mounted filesystems, even those which are not responding - e.g. a hung NFS mount), give df the fileystem(s) you want info on as argument(s).

e.g. instead of:

df -h | grep '/Archive_1

use:

df -h /Archive_1

Now df only tries to get info about the /Archive_1 mount-point. You can use a device node or mount-point as the argument.

With GNU df, you can also use the --output option if all you want is the size...so you don't need to use awk (deleting the first line, i.e. the header, with sed or something is still useful as GNU df doesn't have an option to suppress header output). e.g.

df -h --output=size /Archive_1 | sed 1d

Also, you shouldn't use backticks for command substitution. They're obsolete and deprecated. Use $() instead.

All together, that would be something like:

s_arch_1_per=$(sshpass -p 'password' ssh root@server_ip_1 \
                 'df -h --output=size /Archive_1 | sed 1d')

Finally, you should use key based authentication with ssh, not password auth. But that's an answer for a different question.


BTW, if you still want/need to use awk, you need to escape any $ symbols before field numbers as \$ if it's inside double-quotes. e.g. \$(NF-1) instead of just $(NF-1).

Shell's quoting is a PITA, and that's even more true when you need to do multiple levels of quoting - e.g. when you're sending a quoted awk script to a remote host via ssh.

See Why does my shell script choke on whitespace or other special characters? for all sorts of useful info and tips about shell quoting.

cas
  • 78,579
  • findmnt can be an alternative to df here: findmnt -no size /Archive_1 should just print a human-readable size. – muru May 10 '22 at 15:09