0

我有一个变量,例如:

disk=/dev/sda1

我想提取:

  • 只有非数字部分(即 /dev/sda)
  • 只有数字部分(即 1)

我将在需要磁盘和分区号的脚本中使用它。我怎样才能在 shell 中做到这一点(主要是 bash 和 zsh)?

我正在考虑使用Shell 参数扩展,但在文档中找不到工作模式。

基本上,我试过:

echo ${disk##[:alpha:]}

echo ${disk##[:digit:]}

但没有一个奏效。两人都回来了/dev/sda1

4

3 回答 3

3

使用 bash 和 zsh 以及参数扩展:

disk="/dev/sda12"
echo "${disk//[0-9]/} ${disk//[^0-9]/}"

输出:

/开发/sda 12
于 2019-06-16T18:03:38.663 回答
1

在参数替换中使用模式时必须小心。这些模式不是正则表达式,而是路径名扩展模式或 glob 模式。

想法是删除最后一个数字,因此您要使用删除匹配的后缀模式( ${parameter%%word})。在这里,我们删除了由 描述的匹配模式的最长实例word。使用模式很容易表示单个数字[0-9],但是,多位数字更难。为此,您需要使用扩展的 glob 表达式:

*(pattern-list)匹配给定模式的零次或多次出现

因此,如果要删除最后一个数字,请使用:

$ shopt -s extglob
$ disk="/dev/sda1"
$ echo "${disk#${disk%%*([0-9])}} "${disk%%*([0-9])}"
1 dev/sda
$ disk="/dev/dsk/c0t2d0s0"
$ echo "${disk#${disk%%*([0-9])}} "${disk%%*([0-9])}"
0 /dev/dsk/c0t2d0s

我们必须使用${disk#${disk%%*([0-9])}}删除前缀。它本质上是搜索最后一个数字,删除它,使用剩余部分并再次删除该部分。

您还可以使用带有锚点的模式替换( ${parameter/pattern/string}) 并将%模式锚#定到参数的开头或结尾。(man bash有关更多信息,请参阅)。这完全等同于之前的解决方案:

$ shopt -s extglob
$ disk="/dev/sda1"
$ echo "${disk/${disk/%*([0-9])}/}" "${disk/%*([0-9])}"
1 dev/sda
$ disk="/dev/dsk/c0t2d0s0"
$ echo "${disk/${disk/%*([0-9])}/}" "${disk/%*([0-9])}"
0 /dev/dsk/c0t2d0s
于 2019-06-17T10:57:35.473 回答
1

扩展有点反过来。与[:digit:]您将只匹配一个数字。您需要匹配所有内容,直到或从一个数字开始,因此您需要使用*.

以下看起来不错:

$ echo ${disk%%[0-9]*} ${disk##*[^0-9]}
/dev/sda 1

要使用[:digit:]你需要双括号,因为字符类是[:class:]并且它本身必须在里面[ ]。这就是为什么我更喜欢0-9,少打字*。以下与上述相同:

echo ${disk%%[[:digit:]]*} ${disk##*[^[:digit:]]}

* - 理论上它们可能不相等,因为[0-9]会受到当前语言环境的影响,所以它可能不等于[0123456789],而是不同的东西。

于 2019-06-16T17:26:34.170 回答