• bash 教程 shell 字符串 转义 [MD]


    博文地址

    我的GitHub 我的博客 我的微信 我的邮箱
    baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

    目录

    Bash 字符串

    本文改编自 网道的 Bash 教程,主要为了精简大量本人不感兴趣的内容。

    字符串的表示

    单引号和双引号

    shell 中的字符串可以用单引号,也可以用双引号,也可以不用引号

    单引号中的特殊字符(包括反斜杠)都会变为普通字符,双引号里面的大部分特殊字符会变成普通字符(除了后面提到的三个特殊字符)。

    echo 白 "白" '白'   # 【白 白 白】字符串可以使用双引号、单引号包裹,也可以省略引号
    
    # 引号嵌套
    echo '单中有"双'    # 【单中有"双】,单引号中的双引号不需要转义---单引号中的特殊字符都会变为普通字符
    echo "双中有'单"    # 【双中有'单】,双引号中的单引号不需要转义
    echo 需\"要\'转义   # 【需"要'转义】,没有引号时,双引号、单引号都需要转义
    echo "需要\"转义"   # 【需要"转义】,双引号中的双引号需要转义
    echo "不"需要"转义" # 【不需要转义】,双引号中可成对出现一对双引号,作为字符串拼接使用(其实可认为是两个字符串)
    
    # 单引号中的单引号
    echo it's          # 【(等待输入)】,不正确,等待输入配对的单引号
    echo 'it\'s'       # 【(等待输入)】,单引号中的特殊字符都会变为普通字符,所以单引号中不能使用反斜杠转义
    echo $'it\'s'      # 【it's】,正确,不建议
    echo 'it''s'       # 【its】,正确,单引号中可成对出现一对单引号,作为字符串拼接使用(其实可认为是两个字符串)
    

    转义字符 \

    echo '\'   # 【\】,单引号中的特殊字符都会变为普通字符,包括反斜杠
    echo \     # 【(等待输入)】,按回车后,命令行不会立即执行,而是等待用户继续输入,直到下个回车后才会一并执行
    echo \\    # 【\】,连续使用两个反斜线,可对反斜线自身转义
    
    echo "\\"  # 【\】,双引号里面的大部分特殊字符会变成普通字符,除了【$】【\】【`】
    echo "\"   # 【"】,转义后,由于缺少配对的【"】,所以会等待用户输入匹配的【"】后才会执行
    

    不可打印字符 \n\r\t\b\a

    【\a】响铃、【\b】退格、【\n】换行、【\r】回车、【\t】制表

    echo "a\a\b\n\r\tb" # 【a\a\b\n\r\tb】,默认情况下,双引号和单引号会让不可打印字符变成普通字符
    echo -e "a\tb"      # 【a       b】,放在双引号和单引号里面,并使用【-e】参数,会解释里面的不可打印字符
    
    echo a\b\tc\\td     # 【abtc\td】,不加双引号和单引号时,单独的反斜杠会被忽略,不可打印字符会变成普通字符
    echo -e a\b\tc\\td  # 【abtc    d】,加参数【-e】时,单独的反斜杠会被忽略,但不可打印字符也会被解释
    
    echo a\     # 【(等待输入)】,按回车后,命令行不会立即执行,而是等待用户继续输入,直到下个回车后才会一并执行
    echo "a\    # 【(等待输入)】,同上,等待用户继续输入,直到下个【"+回车】后才会一并执行
    echo 'a\    # 【(等待输入)】,同上,注意,行尾的【\】不会被替换为换行或空格,而是会直接合并两行的内容
    
    pwd;\       # 【(等待输入)】,行尾的反斜杠可以使换行符 \n 变成普通字符,从而可以将一行命令写成多行
    ll
    

    模式扩展字符 ~?*[]{}()$

    a=白
    echo $a "$a"    # 【白 白】,双引号里面的大部分特殊字符会变成普通字符,除了【$】【\】【`】
    echo \$a "\$a"  # 【$a $a】,在特殊字符前面加上反斜杠进行转义(escape)后,可以变为普通字符
    echo '$a \$a'   # 【$a \$a】,单引号中的特殊字符都会变为普通字符
    echo \~ \? \*   # 【~ ? *】,不加反斜杠进行转义时,模式扩展字符会自动扩展(扩展失败时,会变为普通字符)
    

    双引号中的三个特殊字符

    单引号中的特殊字符(包括反斜杠)都会变为普通字符,双引号里面的大部分特殊字符会变成普通字符,但是以下三个特殊字符除外:

    • 美元符号 $:用来引用变量
    • 反斜杠 \:用来转义
    • 反引号 `:执行子命令
    echo `pwd`      # 【/home/bqt】,使用反引号可以显示命令执行的结果
    echo "`pwd`"    # 【/home/bqt】,双引号里面的大部分特殊字符会变成普通字符,除了【$】【\】【`】
    
    echo "hello     # 换行符在双引号之中不再被解释为命令的结束,所以可以利用双引号在命令行输入多行文本
    ls "b qt.txt"   # 文件名包含空格时,必须将文件名放在双引号或单引号里面
    echo "a     b"  # 双引号会原样保存多余的空格
    echo "$(cal)"   # 双引号会保存命令原始的输出格式,不加双引号时会单行输出
    

    使用 Here 文档输入多行字符串

    Here 文档(here document)是一种输入多行字符串的方法,格式如下:

    command << token # 开始标记,由两个小于号 + Here 文档的名称组成,名称可以随意取
    text             # 字符串的内容
    token            # 结束标记,单独一行顶格写的 Here 文档名称
    
    • Here 文档的本质是重定向,它将字符串重定向输出给某个命令,相当于 echo text | command
    • Here 字符串只适合那些可以接受标准输入作为参数的命令,对于 echo 等其他命令无效
    • Here 文档不能作为变量的值,只能用于命令的参数
    • Here 文档内部会发生变量替换,并且双引号和单引号都变成了普通字符
    • Here 文档内部支持反斜杠转义,但是不支持通配符扩展
    a=白
    cat << bqt      # Here 文档内部会发生变量替换,并且双引号和单引号都变成了普通字符
    $a "$a" '$a'    # 【白 "白" '白'】
    bqt
    
    cat << 'bqt'    # 把 Here 文档的开始标记放在单引号之中,可以避免变量替换
    $a "$a" '$a'    # 【$a "$a" '$a'】
    bqt
    

    使用 Here 字符串模拟标准输入

    Here 文档还有一个变体,叫做 Here 字符串(Here string),使用三个小于号(<<<)表示。它的作用是将字符串通过标准输入,传递给命令。

    cat <<< 'aaa'  # 等同于【echo 'aaa' | cat】
    

    有些命令直接接受给定的参数,与通过标准输入接受参数,结果是不一样的。例如cat命令,只能接受标准输入作为参数,如果直接将字符串放在命令后面,会被当作文件名,即cat aaa里面的aaa会被解释成文件名。这时就可以用 Here 字符串,将字符串aaa通过标准输入传给cat命令。

    提取子字符串

    • ${varname:offset}:从第 offset 个字符开始(从0开始计算),截取到字符串的结尾
    • ${varname:offset:length}:从第 offset 个字符开始(从0开始计算),截取 length 个字符
    • ${varname:offset:-length}:从第 offset 个字符开始(从0开始计算),排除末尾的 length 个字符
    • ${varname: -offset}:从倒数第 offset 个字符开始(从1开始计算),截取到字符串的结尾
    • ${varname: -offset:length}:从倒数第 offset 个字符开始(从1开始计算),截取 length 个字符
    • ${varname: -offset:-length}:从倒数第 offset 个字符开始(从1开始计算),排除末尾的 length 个字符

    注意事项:

    • 不能直接操作字符串,只能通过变量名来读取字符串
    • 不会改变原始字符串
    • 负的 -offset 前面必须有一个空格, 以防与 ${variable:-word} 的设置变量默认值语法混淆
    bqt="baiqiantao"
    echo ${#bqt}       # 【10】,字符串的长度
    
    echo ${bqt:3}      # 【qiantao】,从第 3 个字符开始(从 0 开始计算),截取到字符串的结尾
    echo ${bqt:3:4}    # 【qian】,从第 3 个字符开始(从 0 开始计算),截取 4 个字符
    echo ${bqt:3:-1}   # 【qianta】,从第 3 个字符开始(从 0 开始计算),排除末尾的 1 个字符
    
    echo ${bqt: -3}    # 【tao】,从倒数第 3 个字符开始(从 1 开始计算),截取到字符串的结尾
    echo ${bqt: -3:2}  # 【ta】,从倒数第 3 个字符开始(从 1 开始计算),截取 2 个字符
    echo ${bqt: -3:-1} # 【ta】,从倒数第 3 个字符开始(从 1 开始计算),排除末尾的 1 个字符
    
    # 越界情况
    echo ${bqt:11:-1}  # 【空字符串】,如果 offset 越界了,那么直接返回空字符串,后面的 length 无效
    echo ${bqt:10:-1}  # 【报错】,如果 offset 没有越界,那么排除的长度 length 不能超过子字符串的长度
    echo ${bqt: -3:-4} # 【报错】,如果 offset 没有越界,那么排除的长度 length 不能超过子字符串的长度
    echo ${bqt:3:40}-${bqt: -3:40} # 【qiantao-tao】,如果 offset 没有越界,那么截取的长度没有大小限制
    
    # 以下全部返回空字符串
    echo ${bqt:30}-${bqt:30:4}-${bqt:30:-4}-${bqt:30:40}-${bqt:30:-40}
    echo ${bqt: -30}-${bqt: -30:4}-${bqt: -30:-4}-${bqt: -30:40}-${bqt: -30:-40}
    

    替换匹配的字符串

    如果模式匹配成功,就删除匹配的部分,返回剩下的部分(原始变量不会发生变化)。如果匹配不成功,则返回原始字符串。

    字符串头部的模式匹配

    检查 pattern 是否匹配变量 var 的开头

    • ${var#pattern}:如果匹配,则删除最短匹配(又称非贪婪匹配)的部分,返回剩余部分
    • ${var##pattern}:如果匹配,则删除最长匹配(又称贪婪匹配)的部分,返回剩余部分
    • ${var/#pattern/string}:如果匹配,则将匹配的部分替换成 string(可为空) 后返回
    path=/home/bqt/test/hello
    echo ${path#/*/}   # 【bqt/test/hello】,匹配模式【/*/】的最短匹配是【/home/】
    echo ${path##/*/}  # 【hello】,匹配模式【/*/】的最长匹配是【/home/bqt/test/】
    echo ${path#*/}    # 【home/bqt/test/hello】,匹配模式【*/】的最短匹配是【/】
    echo ${path##*/}   # 【hello】,匹配模式【*/】的最长匹配是【/home/bqt/test/】,此模式可用来返回文件名
    
    foo=home/bqt/test/hello
    echo ${foo/#home/xxx}        # 【xxx/bqt/test/hello】,将【home】替换为【xxx】
    echo ${foo/#home*test/xxx}   # 【xxx/hello】,将【home/bqt/test】替换为【xxx】
    echo ${foo/#home*test//xxx}  # 【/xxx/hello】,将【home/bqt/test】替换为【/xxx】
    echo ${foo/#home*test\//xxx} # 【xxxhello】,将【home/bqt/test/】替换为【xxx】
    echo ${foo/##*/xxx}          # 【home/bqt/test/hello】,不支持【##】,匹配模式会识别为【#*】
    

    字符串尾部的模式匹配

    检查 pattern 是否匹配变量 var 的尾部

    • ${var%pattern}:如果匹配,则删除最短匹配(又称非贪婪匹配)的部分,返回剩余部分
    • ${var%%pattern}:如果匹配,则删除最长匹配(又称贪婪匹配)的部分,返回剩余部分
    • ${var/%pattern/string}:如果匹配,则将匹配的部分替换成 string(可为空) 后返回
    path=/home/bqt/test/hello
    echo ${path%t*}     # 【/home/bqt/tes】
    echo ${path%%t*}    # 【/home/bq】
    echo ${path%/*}     # 【/home/bqt/test】,此模式可删除路径的文件名部分,只留下目录部分
    
    echo ${path/%hello/xxx}      # 【/home/bqt/test/xxx】,将【hello】替换为【xxx】
    echo ${path/%b*hello/xxx}    # 【/home/xxx】,将【bqt/test/hello】替换为【xxx】
    echo ${path/%t/*hello/xxx}   # 【/home/bqt/test/hello】,因为不匹配结尾,所以返回原始字符串
    echo ${path/%t\/*hello/xxx}  # 【/home/bqxxx】,将【t/test/hello】替换为【xxx】,贪婪匹配
    echo ${path/%%*/xxx}         # 【home/bqt/test/hello】,不支持【%%】,匹配模式会识别为【%*】
    

    任意位置的模式匹配

    检查 pattern 是否匹配变量 var 的一部分

    • ${var/pattern/string}:如果匹配,则将最长匹配的那部分替换成 string 后返回,仅替换第一个匹配
    • ${var//pattern/string}:如果匹配,则将最长匹配的那部分替换成 string 后返回,所有匹配都替换
    • 如果省略了 string 部分,相当于匹配的部分替换成空字符串,即删除匹配的部分
    path=home/bqt/test/hello
    
    echo ${path/??t/xxx}    # 【home/xxx/test/hello】仅替换第一个匹配
    echo ${path//??t/xxx}   # 【home/xxx/txxx/hello】所有匹配都替换
    echo ${path/\/*t/xxx}   # 【homexxx/hello】最长匹配
    echo ${path//\/*t/xxx}  # 【homexxx/hello】最长匹配
    echo ${path//??t/}      # 【home//t/hello】删除所有匹配的部分
    
    echo -e ${PATH//:/"\n"} # 将环境变量 PATH 中的所有分隔符,由【:】替换成【\n】,并解释为换行符
    

    计算字符位置

    expr index "$var" sub:返回字符串 sub 中的所有字符,在变量 var 中的最小位置

    bqt="baiqiantao"
    echo `expr index "$bqt" a`  #【2】,返回字符 a 在变量中的最小位置
    echo `expr index "$bqt" qa` #【2】,返回字符 q 或 a 在变量中的最小位置
    echo `expr index "$bqt" xy` #【0】,如果所有字符都不存在,则返回 0
    echo `expr index "$bqt" xq` #【4】,忽略不存在的字符 x,返回字符 q 在变量中的最小位置
    

    其他简单操作

    • ${#varname}:字符串的长度
    • ${varname^^}:转为大写
    • ${varname,,}:转为小写
    bqt="baiQianTao"
    echo ${#bqt}  # 【10】,字符串的长度
    echo $#bqt    # 【0bqt】,大括号是必需的,否则会将 $# 理解成脚本的参数个数,将变量名理解成文本
    
    echo ${bqt^^} # 【BAIQIANTAO】,转为大写
    echo ${bqt,,} # 【baiqiantao】,转为小写
    

    2021-12-19

    本文来自博客园,作者:白乾涛,转载请注明原文链接:https://www.cnblogs.com/baiqiantao/p/15708280.html

  • 相关阅读:
    ACdream群赛(4) B Double Kings
    ACdream群赛(4)总结
    250E Mad Joe
    ZOJ Monthly, November 2012 I Search in the Wiki
    251C Number Transformation
    253D Table with Letters 2
    Codeforces Round #153 (Div. 2) 总结
    ACdream群赛(4) D Draw a Mess
    ZOJ Monthly, November 2012 G Gao The Sequence
    在vs2005/c++中捕获浮点数异常
  • 原文地址:https://www.cnblogs.com/baiqiantao/p/15708280.html
Copyright © 2020-2023  润新知