bash + 如何将 arg 与 Linux 机器中的磁盘之一进行比较

yae*_*ael 5 grep bash lsblk

我可以使用以下命令捕获 Linux 机器的磁盘设备:

\n
lsblk -lnb | numfmt --to=iec --field=4 | grep disk | awk '{print $1}'\nsda\nsdb\nsdc\nsdd\n
Run Code Online (Sandbox Code Playgroud)\n

在我的 bash 脚本中,我使用下面的行来测试脚本的参数是否与我的计算机上的磁盘之一匹配:

\n
if [[ ` lsblk -lnb | numfmt --to=iec --field=4 | grep disk | awk '{print $1}' | grep -c $arg ` != 0 ]] \nthen\necho \xe2\x80\x9cargument is a disk\xe2\x80\x9d\n.\n.\n.\n\nfi\n
Run Code Online (Sandbox Code Playgroud)\n

我运行脚本为

\n
bash /tmp/verify_disks  <some arg>\n
Run Code Online (Sandbox Code Playgroud)\n

但如果 case$arg被误认为arg=\xe2\x80\x9d\xe2\x80\x94help\xe2\x80\x9d,或者 case$arg为 null,我会得到以下异常:

\n
Usage: grep [OPTION]... PATTERN [FILE]...\nTry 'grep --help' for more information.\n
Run Code Online (Sandbox Code Playgroud)\n

那么检查$arg我的 Linux 机器中是否包含其中一个磁盘的正确方法是什么?

\n

ter*_*don 8

您似乎没有使用该命令的大部分组件。所有你需要的是:

\n
lsblk -lnb | awk '$NF=="disk"{print $1}'\n
Run Code Online (Sandbox Code Playgroud)\n

然后,为了避免在未给出参数时出现错误消息,您需要引用它,以便grep给出要搜索的内容,即使该内容是空字符串:

\n
if [[ "$(lsblk -lnb | awk '$NF=="disk"{print $1}' | grep -c "$arg")" != 0 ]]; then\n    echo "argument is a disk"\nfi\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
$ echo foo | grep -c ""\n1\n$ echo "" | grep -c ""\n1\n
Run Code Online (Sandbox Code Playgroud)\n

A simple way to avoid the issue\xe2\x80\x94and also a very good habit to get into, you should always check the sanity of your arguments\xe2\x80\x94is to check your argument first:

\n
#!/bin/bash\n\nif [[ -z "$1" ]]; then\n  echo "The script needs at least one non-empty argument"\n  exit 1\nfi\n\n\narg="$1"\n\nif [[ "$(lsblk -lnb | awk '$NF=="disk"{print $1}' | grep -c "$arg")" != 0 ]]; then\n  echo "argument is a disk"\nelse\n  echo "not a disk!"\nfi\n
Run Code Online (Sandbox Code Playgroud)\n


Kus*_*nda 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
Run Code Online (Sandbox Code Playgroud)

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 "useful 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)