9

这是我的情况。目前,我有一个接受两个参数的脚本:书名和章节名。例如:

$ myscript book1 chap1

现在,由于需要很长时间来解释的原因,我希望我的脚本能够采用以下格式的单个参数:{book name}.{chapter name}。例如:

$ myscript book1.chap1

对我来说困难在于我不知道如何将字符串 $1=abc.xyz 转换为两个单独的变量,$var1=abc 和 $var2=xyz。我怎样才能做到这一点?

4

6 回答 6

17

如果只是两个标签,您可以使用 bash 表达式

arg=$1
beforedot=${arg%.*}
afterdot=${arg#*.}

它比cut因为它是内置的 shell 更快。请注意,这会将第一个最后一个点之前的所有内容放入,然后将所有beforedot内容放入afterdot

编辑

如果您想按任意数量的标记进行拆分,还有一个替换/重新解释结构:

string=a.b.c.d.e
tokens=(${string//\./ })

您正在用空格替换点,然后由于它周围的括号而被解释为数组声明+定义。

但是,我发现这对于 bash 的兄弟姐妹和后代来说不太便携。例如,它在我最喜欢的 shell 中不起作用,zsh.

数组需要用大括号取消引用,并从 0 开始索引:

echo "Third token: ${tokens[2]}"

您也可以通过使用 [@] 取消引用整个数组来遍历它们:

for i in ${tokens[@]}
do
    # do stuff
done
于 2012-07-10T15:02:09.767 回答
2

为了完整起见,并且由于您询问了正则表达式方法:

pattern='^([^.]*)\.(.*)'
[[ $1 =~ $pattern ]]
book=${BASH_REMATCH[1]}
chapter=${BASH_REMATCH[2]}

捕获组是BASH_REMATCH数组中的元素。元素 0 包含整个匹配项。

此正则表达式将捕获第一个元素中的第一个点。第一个点之后的任何内容(包括后续点)都将位于第二个元素中。如果需要,可以轻松修改正则表达式以在最后一个点处中断。

于 2012-07-11T01:38:38.383 回答
1

如果$arg包含book.chap

read BOOK CHAP<<<$(IFS="."; echo $arg)

将相应地设置变量 BOOK 和 CHAP。这使用控制 bash 如何理解单词边界的 bash 内部字段分隔符 (IFS)。如果(比如说)您的原始文件中有多个分隔符,$arg那么只需指定更多变量来包含结果。

这里

$IFS 默认为空格(空格、制表符和换行符),但可以更改,例如,解析逗号分隔的数据文件

于 2012-07-10T15:05:40.983 回答
0

您可以使用括号来捕获这两个部分;之后,您可以使用反向引用再次获取它们。不同语言的语法不同;检查http://www.regular-expressions.info/brackets.html了解一般反向引用的课程。

于 2012-07-10T15:00:32.683 回答
0
#!/bin/bash

book=${1%.*}
chapter=${1#*.}

printf 'book: %s\nchapter: %s\n' "$book" "$chapter"
于 2012-07-10T15:04:07.490 回答
0

带壳参数展开的模式替换

有很多方法可以完成你想做的事情。其他答案中未涵盖的一种方法是模式替换

如果您知道该值将始终在一个句点上正确拆分,则可以将模式替换应用于该值,以便使用IFS轻松标记化。例如:

set -- foo.bar
myvar="${1/./ }"
echo $myvar

这将产生foo bar.

于 2012-07-10T15:27:48.950 回答