这是我的情况。目前,我有一个接受两个参数的脚本:书名和章节名。例如:
$ myscript book1 chap1
现在,由于需要很长时间来解释的原因,我希望我的脚本能够采用以下格式的单个参数:{book name}.{chapter name}。例如:
$ myscript book1.chap1
对我来说困难在于我不知道如何将字符串 $1=abc.xyz 转换为两个单独的变量,$var1=abc 和 $var2=xyz。我怎样才能做到这一点?
如果只是两个标签,您可以使用 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
为了完整起见,并且由于您询问了正则表达式方法:
pattern='^([^.]*)\.(.*)'
[[ $1 =~ $pattern ]]
book=${BASH_REMATCH[1]}
chapter=${BASH_REMATCH[2]}
捕获组是BASH_REMATCH
数组中的元素。元素 0 包含整个匹配项。
此正则表达式将捕获第一个元素中的第一个点。第一个点之后的任何内容(包括后续点)都将位于第二个元素中。如果需要,可以轻松修改正则表达式以在最后一个点处中断。
如果$arg
包含book.chap
read BOOK CHAP<<<$(IFS="."; echo $arg)
将相应地设置变量 BOOK 和 CHAP。这使用控制 bash 如何理解单词边界的 bash 内部字段分隔符 (IFS)。如果(比如说)您的原始文件中有多个分隔符,$arg
那么只需指定更多变量来包含结果。
从这里:
$IFS 默认为空格(空格、制表符和换行符),但可以更改,例如,解析逗号分隔的数据文件
您可以使用括号来捕获这两个部分;之后,您可以使用反向引用再次获取它们。不同语言的语法不同;检查http://www.regular-expressions.info/brackets.html了解一般反向引用的课程。
#!/bin/bash
book=${1%.*}
chapter=${1#*.}
printf 'book: %s\nchapter: %s\n' "$book" "$chapter"
有很多方法可以完成你想做的事情。其他答案中未涵盖的一种方法是模式替换。
如果您知道该值将始终在一个句点上正确拆分,则可以将模式替换应用于该值,以便使用IFS轻松标记化。例如:
set -- foo.bar
myvar="${1/./ }"
echo $myvar
这将产生foo bar
.