4

I can capture the disk devices of my Linux machine with the following command:

lsblk -lnb | numfmt --to=iec --field=4 | grep disk | awk '{print $1}'
sda
sdb
sdc
sdd

In my bash script I used the line below to test if the script's argument matches one of the disks on my machine:

if [[ ` lsblk -lnb | numfmt --to=iec --field=4 | grep disk | awk '{print $1}' | grep -c $arg ` != 0 ]] 
then
echo “argument is a disk”
.
.
.

fi

I run the script as

bash /tmp/verify_disks  <some arg>

But in case $arg is by mistake as arg=”—help” , or in case $arg is null, I get the following exception:

Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.

So what is the right approach to check if $arg includes one of the disks in my Linux machines without exception?

0

3 Answers 3

7

You don't seem to be using most of the components of that command. All you need is:

lsblk -lnb | awk '$NF=="disk"{print $1}'

Then, to avoid the error message when no argument has been given, you need to quote it so grep is given something to search for even if that something is an empty string:

if [[ "$(lsblk -lnb | awk '$NF=="disk"{print $1}' | grep -c "$arg")" != 0 ]]; then
    echo "argument is a disk"
fi

However, this will return "argument is a disk" when you give it nothing since anything, including an empty line, matches the empty string:

$ echo foo | grep -c ""
1
$ echo "" | grep -c ""
1

A simple way to avoid the issue—and also a very good habit to get into, you should always check the sanity of your arguments—is to check your argument first:

#!/bin/bash

if [[ -z "$1" ]]; then
  echo "The script needs at least one non-empty argument"
  exit 1
fi


arg="$1"

if [[ "$(lsblk -lnb | awk '$NF=="disk"{print $1}' | grep -c "$arg")" != 0 ]]; then
  echo "argument is a disk"
else
  echo "not a disk!"
fi
6

Since lsblk allows for JSON output, it seems natural to use jq with it to figure out whether the given argument is a disk or not:

#!/bin/sh

if lsblk -J | jq -e --arg name "$1" '.blockdevices[] | select(.type == "disk" and .name == $name)' >/dev/null
then
    printf '"%s" is a disk\n' "$1"
else
    printf '"%s" is not a disk\n' "$1"
fi

This correctly handles the cases where the first argument to the script is empty, missing or nonsense.

The -e option to jq makes the utility exit with an exit status dependent on the last value evaluated. It will be non-zero if the last expression evaluated (the select()) is null, for example.

5

One possibility is to have two if-checks. At first, check if you can use $1 (the first argument) (it is not zero and is not --help) and then compare it to your lsblk-Output. For example:

#!/bin/env bash
if [[ -z "${1}" ]] || [[ "--help" == ${1} ]]; then
    echo "usefull usage goes here"
else
    if [[ ` lsblk -lnb | numfmt --to=iec --field=4 | grep disk | awk '{print $1}' | grep -c ${1} ` != 0 ]]; then
        echo "argument is a disk"
    fi
fi

Another tip: Why are you formatting the output of lsblk, if you aren't interested in it? And why are you grepping for the "disk" lines, when lsblk can give you only the disk-lines? So the if-statement could be shortened to something like that (at least, if your version of lsblk knows -d):

if lsblk -dn | awk '{ print $1 }' | grep -wq $1; then

Or, even shorter (thanks for the hint, muru (I should have paid more attention to the man-page...)):

if lsblk -dn -o name | grep -wq $1; then
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.