Java字符串替换前缀_bash 进阶之变量替换与字符串操作

摘自《高级bash脚本编程指南》

变量替换

处理和(或)扩展变量

${parameter}

与$parameter相同, 也就是变量parameter的值. 在某些上下文中, ${parameter}很少会产生混淆.

可以把变量和字符串组合起来使用.1 your_id=${USER}-on-${HOSTNAME}

2 echo "$your_id"

3 #

4 echo "Old \$PATH = $PATH"

5 PATH=${PATH}:/opt/bin #在脚本的生命周期中, /opt/bin会被添加到$PATH变量中.

6 echo "New \$PATH = $PATH"

${parameter-default}, ${parameter:-default}

${parameter-default} — 如果变量parameter没被声明, 那么就使用默认值.

${parameter:-default} — 如果变量parameter没被设置, 那么就使用默认值.

注:“(没)被声明”与“(没)被设置”在是否有 “:” 号的句式差别中仅仅是触发点的不同而已。“被声明”的触发点显然要比“被设置”的要低,“被设置”是在“被声明”的基础上而且不能赋值(设置)为空(没有赋值/设置为空)。1 echo ${username-`whoami`}

2 # 如果变量$username还没有被声明, 那么就echo出`whoami`的结果(译者注: 也就是把'whoami'的结果赋值给变量$username).

注:${parameter-default} 和${parameter:-default}在绝大多数的情况下都是相同的. 只有在parameter已经被声明, 但是被赋null值得时候, 这个额外的 : 才会产生不同的结果.1 #!/bin/bash

2 # param-sub.sh

3

4 # 一个变量是否被声明或设置,

5 #+ 将会影响这个变量是否使用默认值,

6 #+ 即使这个变量值为空(null).

7

8 username0=

9 echo "username0 has been declared, but is set to null."

10 echo "username0 = ${username0-`whoami`}"

11 # 不会有输出.

12

13 echo

14

15 echo username1 has not been declared.

16 echo "username1 = ${username1-`whoami`}"

17 # 将会输出默认值.

18

19 username2=

20 echo "username2 has been declared, but is set to null."

21 echo "username2 = ${username2:-`whoami`}"

22 # ^

23 # 会输出, 因为:-会比-多一个条件测试.

24 # 可以与上边的例子比较一下.

25

26

27 #

28

29 # 再来一个:

30

31 variable=

32 # 变量已经被声明, 但是设为空值.

33

34 echo "${variable-0}" # (没有输出)

35 echo "${variable:-1}" # 1

36 # ^

37

38 unset variable

39

40 echo "${variable-2}" # 2

41 echo "${variable:-3}" # 3

42

43 exit 0

如果脚本并没有接收到来自命令行的参数, 那么默认参数结构将会提供一个默认值给脚本.1 DEFAULT_FILENAME=generic.data

2 filename=${1:-$DEFAULT_FILENAME} #对 $1 设置默认值

3 # 如果没有指定值, 那么下面的代码块将会使用filename

4 #+ 变量的默认值"generic.data".

5 #

6 # 后续的命令.

${parameter=default}, ${parameter:=default}

${parameter=default} — 如果变量parameter没被声明, 那么就把它的值设为default.

${parameter:=default} — 如果变量parameter没被设置, 那么就把它的值设为default.

这两种形式基本上是一样的. 只有在变量$parameter被声明并且被设置为null值的时候, : 才会引起这两种形式的不同. 如上边所示.1 echo ${username=`whoami`}

2 # 变量"username"现在被赋值为`whoami`.

${parameter+alt_value}, ${parameter:+alt_value}

${parameter+alt_value} — 如果变量parameter被声明了, 那么就使用alt_value, 否则就使用null字符串.

${parameter:+alt_value} — 如果变量parameter被设置了, 那么就使用alt_value, 否则就使用null字符串.

这两种形式绝大多数情况下都一样. 只有在parameter被声明并且设置为null值的时候, 多出来的这个: 才会引起这两种形式的不同, 具体请看下边的例子.1 echo "###### \${parameter+alt_value} ########"

2 echo

3

4 a=${param1+xyz}

5 echo "a = $a" # a =

6

7 param2=

8 a=${param2+xyz}

9 echo "a = $a" # a = xyz

10

11 param3=123

12 a=${param3+xyz}

13 echo "a = $a" # a = xyz

14

15 echo

16 echo "###### \${parameter:+alt_value} ########"

17 echo

18

19 a=${param4:+xyz}

20 echo "a = $a" # a =

21

22 param5=

23 a=${param5:+xyz}

24 echo "a = $a" # a =

25 # 产生与a=${param5+xyz}不同的结果.

26

27 param6=123

28 a=${param6:+xyz}

29 echo "a = $a" # a = xyz

${parameter?err_msg}, ${parameter:?err_msg}

${parameter?err_msg} — 如果parameter被声明了, 那么就使用设置的值, 否则打印err_msg错误消息.

${parameter:?err_msg} — 如果parameter被设置了, 那么就使用设置的值, 否则打印err_msg错误消息.

这两种形式绝大多数情况都是一样的. 和上边所讲的情况一样, 只有在parameter被声明并设置为null值的时候, 多出来的 : 才会引起这两种形式的不同.

例子 1. 使用参数替换和错误消息1 #!/bin/bash

2

3 # 检查一些系统环境变量.

4 # 这是一种可以做一些预防性保护措施的好习惯.

5 # 比如, 如果$USER(用户在控制台上中的名字)没有被设置的话,

6 #+ 那么系统就会不认你.

7

8 : ${HOSTNAME?} ${USER?} ${HOME?} ${MAIL?}

9 echo

10 echo "Name of the machine is $HOSTNAME."

11 echo "You are $USER."

12 echo "Your home directory is $HOME."

13 echo "Your mail INBOX is located in $MAIL."

14 echo

15 echo "If you are reading this message,"

16 echo "critical environmental variables have been set."

17 echo

18 echo

19

20 # ------------------------------------------------------

21

22 # ${variablename?}结构

23 #+ 也能够检查脚本中变量的设置情况.

24

25 ThisVariable=Value-of-ThisVariable

26 # 注意, 顺便提一下,

27 #+ 这个字符串变量可能会被设置一些非法字符.

28 : ${ThisVariable?}

29 echo "Value of ThisVariable is $ThisVariable".

30 echo

31 echo

32

33

34 : ${ZZXy23AB?"ZZXy23AB has not been set."}

35 # 如果变量ZZXy23AB没有被设置的话,

36 #+ 那么这个脚本会打印一个错误信息, 然后结束.

37

38 # 你可以自己指定错误消息.

39 # : ${variablename?"ERROR MESSAGE"}

40

41

42 # 等价于: dummy_variable=${ZZXy23AB?}

43 # dummy_variable=${ZZXy23AB?"ZXy23AB has not been set."}

44 # (dummy 的意思是“虚设的、假的、名义上的”)

45 # echo ${ZZXy23AB?} >/dev/null

46 (me:到这里俺终于明白特殊符号 ":" 在一个二元命令中提供一个占位符和默认参数的意思了。确切来说是明白了所谓的“二元命令”指啥了,扯远了,^_^)

1 : ${username=`whoami`}

2 # ${username=`whoami`} 如果没有开头的":"的话, 将会给出一个错误,

3 # 除非"username"是一个命令或者内建命令...

47 # 使用命令"set -u"来比较这些检查变量是否被设置的方法.

48 #

49

50

51

52 echo "You will not see this message, because script already terminated."

53

54 HERE=0

55 exit $HERE # 不会在这里退出.

56

57 # 事实上, 这个脚本将会以返回值1作为退出状态(echo $?).

例子 2. 参数替换和”usage”消息(译者注: 通常就是帮助信息)1 #!/bin/bash

2 # usage-message.sh

3

4 : ${1?"Usage: $0 ARGUMENT"}

5 # 如果没有提供命令行参数的话, 那么脚本就在这里退出了,

6 #+ 并且打印如下错误消息.

7 # usage-message.sh: 1: Usage: usage-message.sh ARGUMENT

8

9 echo "These two lines echo only if command-line parameter given."

10 echo "command line parameter = \"$1\""

11

12 exit 0 # 如果提供了命令行参数, 那么脚本就会在这里退出.

13

14 # 分别检查有命令行参数时和没有命令行参数时, 脚本的退出状态.

15 # 如果有命令行参数, 那么"$?"就是0.

16 # 如果没有的话, 那么"$?"就是1.

参数替换与(或)扩展.

下边这些表达式都是对如何在expr字符串操作中进行match的补充. 这些特定的使用方法一般都用来解析文件所在的目录名.

变量长度/子串删除

${#var}

字符串长度(变量$var得字符个数). 对于array来说, ${#array}表示的是数组中第一个元素的长度.

例外情况:${#*}和${#@}表示位置参数的个数.

对于数组来说, ${#array[*]}和${#array[@]}表示数组中元素的个数.

例子 3. 变量长度1 #!/bin/bash

2 # length.sh

3

4 E_NO_ARGS=65

5

6 if [ $# -eq 0 ] # 这个演示脚本必须有命令行参数. 特殊变量 $# 表示命令行参数的个数。

7 then

8 echo "Please invoke this script with one or more command-line arguments."

9 exit $E_NO_ARGS

10 fi

11

12 var01=abcdEFGH28ij

13 echo "var01 = ${var01}"

14 echo "Length of var01 = ${#var01}"

15 # 现在, 让我们试试在变量中嵌入一个空格.

16 var02="abcd EFGH28ij"

17 echo "var02 = ${var02}"

18 echo "Length of var02 = ${#var02}"

19

20 echo "Number of command-line arguments passed to script = ${#@}"

21 echo "Number of command-line arguments passed to script = ${#*}"

22

23 exit 0

${var#Pattern}, ${var##Pattern}

从变量 $var 的开头删除最短或最长匹配 $Pattern 的子串. (译者注: 这是一个很常见的用法, 请读者牢记, 一个”#”表示匹配最短, “##”表示匹配最长.)

用法示例:1 # 摘自例子"days-between.sh"的一个函数.

2 # 去掉传递进来参数开头的0.

3

4 strip_leading_zero () # 去掉从参数中传递进来的,

5 { #+ 可能存在的开头的0(也可能有多个0).

6 return=${1#0} # "1"表示的是"$1" -- 传递进来的参数.

7 } # "0"就是我们想从"$1"中删除的子串 -- 去掉零.

另一个用法示例:1 echo `basename $PWD` # 当前工作目录的basename(就是去掉目录名).

2 echo "${PWD##*/}" # 当前工作目录的basename(就是去掉目录名).

3 echo

4 echo `basename $0` # 脚本名字.

5 echo $0 # 脚本名字.

6 echo "${0##*/}" # 脚本名字."0" 表示 "$0"

7 echo

8 filename=test.data

9 echo "${filename##*.}" # data

10 # 文件扩展名.

${var%Pattern}, ${var%%Pattern}

从变量 $var 的结尾删除最短或最长匹配 $Pattern 的子串. (译者注: 这是一个很常见的用法, 请读者牢记, 一个”%”表示匹配最短, “%%”表示匹配最长.)

例子 4. 修改文件扩展名:1 #!/bin/bash

2 # rfe.sh: 修改文件扩展名.

3 #

4 # 用法:rfe old_extension new_extension

5 #

6 # 示例:

7 # 将指定目录中所有的*.gif文件都重命名为*.jpg,

8 # 用法:rfe gif jpg

9

10

11 E_BADARGS=65

12

13 case $# in

14 0|1) # 竖线"|"在这里表示"或"操作.

15 echo "Usage: `basename $0` old_file_suffix new_file_suffix"

16 exit $E_BADARGS # 如果只有0个或1个参数的话, 那么就退出脚本.

17 ;;

18 esac

19

20

21 for filename in *.$1

22 # 以第一个参数为扩展名的全部文件的列表.

23 do

24 mv $filename ${filename%$1}$2

25 # 把筛选出来的文件的扩展名去掉, 因为筛选出来的文件的扩展名都是第一个参数,

26 #+ 然后把第2个参数作为扩展名, 附加到这些文件的后边.

27 done

28

29 exit 0

变量扩展/子串替换 这些结构都是从ksh中引入的.

${var:pos}

变量var从位置pos开始扩展(译者注: 也就是pos之前的字符都丢弃).

${var:pos:len}

变量var从位置pos开始, 并扩展len个字符.

${var/Pattern/Replacement}

使用Replacement来替换变量var中第一个匹配 Pattern 的字符串.

如果省略Replacement, 那么第一个匹配Pattern的字符串将被替换为空, 也就是被删除了.

${var//Pattern/Replacement}

全局替换. 所有在变量var匹配Pattern的字符串, 都会被替换为Replacement.

和上边一样, 如果省略Replacement, 那么所有匹配Pattern的字符串, 都将被替换为空, 也就是被删除掉.

(Pattern 为正则表达式)

例子 5. 使用模式匹配来解析任意字符串1 #!/bin/bash

2

3 var1=abcd-1234-defg

4 echo "var1 = $var1"

5

6 t=${var1#*-*}

7 echo "var1 (with everything, up to and including first - stripped out) = $t"

8 # t=${var1#*-} 也一样,

9 #+ 因为#匹配最短的字符串,

10 #+ 同时*匹配任意前缀, 包括空字符串. (上面的语句执行后 $t 的值为 "123-defg")

11 # (感谢, Stephane Chazelas, 指出这点.)

12

13 t=${var1##*-*}

14 echo "If var1 contains a \"-\", returns empty string... var1 = $t"

15

16

17 t=${var1%*-*}

18 echo "var1 (with everything from the last - on stripped out) = $t"

19

20 echo

21

22 # -------------------------------------------

23 path_name=/home/bozo/ideas/thoughts.for.today

24 # -------------------------------------------

25 echo "path_name = $path_name"

26 t=${path_name##/*/}

27 echo "path_name, stripped of prefixes = $t"

28 # 在这个特例中, 与t=`basename $path_name`效果相同.

29 # t=${path_name%/}; t=${t##*/} 是更一般的解决方法.

30 #+ 但有时还是会失败.

31 # 如果$path_name以一个换行符结尾的话, 那么`basename $path_name` 就不能正常工作了,

32 #+ 但是上边的表达式可以.

33 # (感谢, S.C.)

34

35 t=${path_name%/*.*}

36 # 与t=`dirname $path_name`效果相同.

37 echo "path_name, stripped of suffixes = $t"

38 # 在某些情况下将失效, 比如 "../", "/foo", # "foo/", "/".

39 # 删除后缀, 尤其是在basename没有后缀的情况下,

40 #+ 但是dirname可以, 不过这同时也使问题复杂化了.

41 # (感谢, S.C.)

42

43 echo

44

45 t=${path_name:11} # bash 的索引从 “0” 开始计数

46 echo "$path_name, with first 11 chars stripped off = $t"

47 t=${path_name:11:5}

48 echo "$path_name, with first 11 chars stripped off, length 5 = $t"

49

50 echo

51

52 t=${path_name/bozo/clown}

53 echo "$path_name with \"bozo\" replaced by \"clown\" = $t"

54 t=${path_name/today/}

55 echo "$path_name with \"today\" deleted = $t"

56 t=${path_name//o/O}

57 echo "$path_name with all o's capitalized = $t"

58 t=${path_name//o/}

59 echo "$path_name with all o's deleted = $t"

60

61 exit 0

${var/#Pattern/Replacement}

如果变量var的前缀匹配Pattern, 那么就使用Replacement来替换匹配到Pattern的字符串.

${var/%Pattern/Replacement}

如果变量var的后缀匹配Pattern, 那么就使用Replacement来替换匹配到Pattern的字符串.

例子 6. 对字符串的前缀和后缀使用匹配模式1 #!/bin/bash

2 # var-match.sh:

3 # 对字符串的前缀和后缀进行模式替换的一个演示.

4

5 v0=abc1234zip1234abc # 变量原始值.

6 echo "v0 = $v0" # abc1234zip1234abc

7 echo

8

9 # 匹配字符串的前缀(开头).

10 v1=${v0/#abc/ABCDEF} # abc1234zip1234abc

11 # |-|

12 echo "v1 = $v1" # ABCDEF1234zip1234abc

13 # |----|

14

15 # 匹配字符串的后缀(结尾).

16 v2=${v0/%abc/ABCDEF} # abc1234zip123abc

17 # |-|

18 echo "v2 = $v2" # abc1234zip1234ABCDEF

19 # |----|

20

21 echo

22

23 # ----------------------------------------------------

24 # 必须匹配字符串的开头或结尾,

25 #+ 否则是不会产生替换结果的.

26 # ----------------------------------------------------

27 v3=${v0/#123/000} # 匹配, 但不是在开头.

28 echo "v3 = $v3" # abc1234zip1234abc

29 # 不会发生替换.

30 v4=${v0/%123/000} # 匹配, 但不是在结尾.

31 echo "v4 = $v4" # abc1234zip1234abc

32 # 不会发生替换.

33

34 exit 0

${!varprefix*}, ${!varprefix@}

匹配所有之前声明过的, 并且以varprefix开头的变量.1 xyz23=whatever

2 xyz24=

3

4 a=${!xyz*} # 展开所有以"xyz"开头的, 并且之前声明过的变量名.

5 echo "a = $a" # a = xyz23 xyz24

6 a=${!xyz@} # 同上.

7 echo "a = $a" # a = xyz23 xyz24

8

9 # Bash, 版本2.04, 添加了这个功能.

字符串操作

Bash所支持的字符串操作的数量多的令人惊讶. 但是不幸的是, 这些工具缺乏统一的标准. 一些是参数替换的子集, 而另外一些则受到UNIX expr命令的影响. 这就导致了命令语法的不一致, 还会引起冗余的功能, 但是这些并没有引起混乱.

字符串长度

${#string}

expr length $string

expr “$string” : ‘.*’

匹配字符串开头的子串长度

expr match “$string” ‘$substring’

$substring是一个正则表达式.

expr “$string” : ‘$substring’

$substring是一个正则表达式.1 stringZ=abcABC123ABCabc

2 # |------|

3

4 echo `expr match "$stringZ" 'abc[A-Z]*.2'` # 8

5 echo `expr "$stringZ" : 'abc[A-Z]*.2'` # 8

索引

expr index $string $substring

在字符串$string中所匹配到的$substring第一次所出现的位置.

提取子串

${string:position}

在$string中从位置$position开始提取子串.

如果$string是”*”或者”@”, 那么将会提取从位置$position开始的位置参数. (这适用于命令行参数或函数参数.)

${string:position:length}

在$string中从位置$position开始提取$length长度的子串.1 stringZ=abcABC123ABCabc

2 # 0123456789.....

3 # 0-based indexing.

4

5 echo ${stringZ:0} # abcABC123ABCabc

6 echo ${stringZ:1} # bcABC123ABCabc

7 echo ${stringZ:7} # 23ABCabc

8

9 echo ${stringZ:7:3} # 23A

10 # 提取子串长度为3.

11

12

13

14 # 能不能从字符串的右边(也就是结尾)部分开始提取子串?

15

16 echo ${stringZ:-4} # abcABC123ABCabc

17 # 默认是提取整个字符串, 就象${parameter:-default}一样.

18 # 然而 . . .

19

20 echo ${stringZ:(-4)} # Cabc

21 echo ${stringZ: -4} # Cabc

22 # 这样, 它就可以工作了.

23 # 使用圆括号或者添加一个空格可以"转义"这个位置参数.

24

25 # 感谢, Dan Jacobson, 指出这点.

如果$string参数是”*”或”@”, 那么将会从$position位置开始提取$length个位置参数, 但是由于可能没有$length个位置参数了, 那么就有几个位置参数就提取几个位置参数.1 echo ${*:2} # 打印出第2个和后边所有的位置参数.

2 echo ${@:2} # 同上.

3

4 echo ${*:2:3} # 从第2个开始, 连续打印3个位置参数.

expr substr $string $position $length

在$string中从$position开始提取$length长度的子串.1 stringZ=abcABC123ABCabc

2 # 123456789......

3 # 以1开始计算.

4

5 echo `expr substr $stringZ 1 2` # ab

6 echo `expr substr $stringZ 4 3` # ABC

expr match “$string” ‘\($substring\)’

从$string的开始位置提取$substring, $substring是正则表达式.

expr “$string” : ‘\($substring\)’

从$string的开始位置提取$substring, $substring是正则表达式.1 stringZ=abcABC123ABCabc

2 # =======

3

4 echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1

5 echo `expr "$stringZ" : '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1

6 echo `expr "$stringZ" : '\(.......\)'` # abcABC1

7 # 上边的每个echo都打印出相同的结果.

expr match “$string” ‘.*\($substring\)’

从$string的结尾提取$substring, $substring是正则表达式.

expr “$string” : ‘.*\($substring\)’

从$string的结尾提取$substring, $substring是正则表达式.1 stringZ=abcABC123ABCabc

2 # ======

3

4 echo `expr match "$stringZ" '.*\([A-C][A-C][A-C][a-c]*\)'` # ABCabc

5 echo `expr "$stringZ" : '.*\(......\)'` # ABCabc

子串削除

${string#substring}

从$string的开头位置截掉最短匹配的$substring.

${string##substring}

从$string的开头位置截掉最长匹配的$substring.

${string%substring}

从$string的结尾位置截掉最短匹配的$substring.

${string%%substring}

从$string的结尾位置截掉最长匹配的$substring.

当你需要构造文件名的时候, 这个操作就显得特别有用.(例如更改文件后缀名(格式)等)

子串替换

${string/substring/replacement}

使用$replacement来替换第一个匹配的$substring.

${string//substring/replacement}

使用$replacement来替换所有匹配的$substring.

${string/#substring/replacement}

如果$substring匹配$string的开头部分, 那么就用$replacement来替换$substring.

${string/%substring/replacement}

如果$substring匹配$string的结尾部分, 那么就用$replacement来替换$substring.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值