├── assets ├── logger-01.png ├── logger-11.png └── logger-12.png ├── libs ├── base.sh ├── date.sh ├── fs.sh ├── http.sh ├── logger.sh ├── math.sh ├── path.sh ├── proc.sh ├── str.sh └── url.sh ├── readme.md └── sample ├── bash编程规范.md ├── http_doc.md ├── logger_doc.md ├── logger_test.sh ├── proc_doc.md ├── str_doc.md ├── str_test.sh ├── url_doc.md └── url_test.sh /assets/logger-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generals-space/bash-libs/6d04339b0f9e303eff68cc3bedac9d1b8ef815c2/assets/logger-01.png -------------------------------------------------------------------------------- /assets/logger-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generals-space/bash-libs/6d04339b0f9e303eff68cc3bedac9d1b8ef815c2/assets/logger-11.png -------------------------------------------------------------------------------- /assets/logger-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generals-space/bash-libs/6d04339b0f9e303eff68cc3bedac9d1b8ef815c2/assets/logger-12.png -------------------------------------------------------------------------------- /libs/base.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generals-space/bash-libs/6d04339b0f9e303eff68cc3bedac9d1b8ef815c2/libs/base.sh -------------------------------------------------------------------------------- /libs/date.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## @function: 返回当前时间的时间戳. 4 | ## @note: 注意位数, 与python相同, 但比js少3位 5 | ## @return: 结果以echo方式返回. 6 | function now() 7 | { 8 | echo -n $(date +'%s') 9 | } 10 | 11 | function get_std_date() 12 | { 13 | echo -n $(date +'%Y/%m/%d %H:%M:%S') 14 | } 15 | -------------------------------------------------------------------------------- /libs/fs.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generals-space/bash-libs/6d04339b0f9e303eff68cc3bedac9d1b8ef815c2/libs/fs.sh -------------------------------------------------------------------------------- /libs/http.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generals-space/bash-libs/6d04339b0f9e303eff68cc3bedac9d1b8ef815c2/libs/http.sh -------------------------------------------------------------------------------- /libs/logger.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | __LOGGER_LEVEL_DEBUG__=1 4 | __LOGGER_LEVEL_INFO__=2 5 | __LOGGER_LEVEL_WARN__=3 6 | __LOGGER_LEVEL_ERROR__=4 7 | 8 | __LOGGER_LOG_LEVEL__=$__LOGGER_LEVEL_INFO__ 9 | 10 | function _get_now() 11 | { 12 | echo -n $(date +'[%Y/%m/%d %H:%M:%S]') 13 | } 14 | 15 | ########################################################## 16 | ## 日志打印函数, 按等级输出 17 | 18 | ## 知识点 19 | ## 双小括号内可以使用> >=, ==, <=, <等高级语言的逻辑运算符 20 | ## 且双小括号内引用变量不必加$前缀 21 | ## 为了使用输出信息左侧对齐, DEBUG, INFO等冒号之间与$1参数的空格是不同的. 22 | 23 | ########################################################## 24 | ## 颜色打印只适合在终端输出, 如果输出到文件会乱码, 所以log_XXX用于写入日志文件. 25 | function log_debug() 26 | { 27 | if (( __LOGGER_LOG_LEVEL__ <= __LOGGER_LEVEL_DEBUG__ )); then 28 | echo "$(_get_now) DEBUG: $1" 29 | fi 30 | } 31 | function log_info() 32 | { 33 | if (( __LOGGER_LOG_LEVEL__ <= __LOGGER_LEVEL_INFO__ )); then 34 | echo "$(_get_now) INFO: $1" 35 | fi 36 | } 37 | function log_warn() 38 | { 39 | if (( __LOGGER_LOG_LEVEL__ <= __LOGGER_LEVEL_WARN__ )); then 40 | echo "$(_get_now) WARN: $1" 41 | fi 42 | } 43 | function log_error() 44 | { 45 | if (( __LOGGER_LOG_LEVEL__ <= __LOGGER_LEVEL_ERROR__ )); then 46 | echo "$(_get_now) ERROR: $1" 47 | fi 48 | } 49 | ## log_success不判断等级, 只是一个工具函数, 因为ta打印的是绿色字符. 50 | function log_success() 51 | { 52 | echo "$(_get_now) SUCCESS: $1" 53 | } 54 | ########################################################## 55 | ## 颜色打印日志 56 | ## echo -e不转义反斜线, 因为要输出颜色信息 57 | ## 注意$1使用双引号包裹, 这是因为如果传入的参数包含空格时不会分隔. 58 | function clog_debug() 59 | { 60 | echo -e "\033[34m$(log_debug "$1")\033[0m" 61 | } 62 | function clog_info() 63 | { 64 | echo -e "$(log_info "$1") \033[0m" 65 | } 66 | function clog_warn() 67 | { 68 | echo -e "\033[33m$(log_warn "$1")\033[0m" 69 | } 70 | function clog_error() 71 | { 72 | echo -e "\033[31m$(log_error "$1")\033[0m" 73 | } 74 | 75 | function clog_success() 76 | { 77 | echo -e "\033[32m$(log_success "$1")\033[0m" 78 | } 79 | 80 | ########################################################## 81 | ## 彩色打印函数, 与日志等级无关, 只作为工具函数 82 | function print() 83 | { 84 | echo -e "$1 " 85 | } 86 | function print_blue() 87 | { 88 | echo -e "\033[34m$1 \033[0m" 89 | } 90 | function print_green() 91 | { 92 | echo -e "\033[32m$1 \033[0m" 93 | } 94 | function print_yellow() 95 | { 96 | echo -e "\033[33m$1 \033[0m" 97 | } 98 | function print_red() 99 | { 100 | echo -e "\033[31m$1 \033[0m" 101 | } 102 | -------------------------------------------------------------------------------- /libs/math.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | -------------------------------------------------------------------------------- /libs/path.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function pathjoin() 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /libs/proc.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generals-space/bash-libs/6d04339b0f9e303eff68cc3bedac9d1b8ef815c2/libs/proc.sh -------------------------------------------------------------------------------- /libs/str.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## @function: 计算指定字符串的长度 4 | ## $1: 目标字符串 5 | function strlen() 6 | { 7 | ## 1. wc 的-L选项, 直接获取当前行的字符数 8 | ## wc的选项可能由于不同系统平台而不同, 所以尽量不考虑这种方式. 9 | ## echo $1 | wc -L 10 | ## 2. ${}方法, 把字符串变量当作是数组处理 11 | echo ${#1} 12 | ## 3. awk内置的length()函数 13 | ## echo $1 | awk '{print length($0)}' 14 | ## 4. expr内置lenght无法处理变量中存在空格的情形, 放弃使用 15 | } 16 | 17 | ## @function: 移除参数$1左右两侧的空白字符 18 | function strtrim() 19 | { 20 | : 21 | } 22 | function strltrim() 23 | { 24 | : 25 | } 26 | function strrtrim() 27 | { 28 | : 29 | } 30 | ## @function: 判断$2是否为$1的子字符串, 即$1是否包含$2. 31 | ## @note: bash中花括号的高级应用, 判断从$1开始处是否可以匹配到`*$2*`, `*`为通配符. 32 | ## 是, 则从$1左侧移除匹配的部分并返回剩下的部分, 否则直接返回$1. 33 | ## 另外注意包裹的双引号. 34 | ## @return: 结果以echo方式返回 35 | function strcontains() 36 | { 37 | if [ "${1#*$2}" = "$1" ]; then 38 | echo 0 39 | else 40 | echo 1 41 | fi 42 | } 43 | ## @function: 判断$1是否以$2起始 44 | ## @return: 结果以echo方式返回 45 | function strstartwith() 46 | { 47 | if [[ "${1#$2}" = "$1" ]]; then 48 | echo 0 49 | else 50 | echo 1 51 | fi 52 | } 53 | ## @function: 判断$1是否以$2结尾 54 | ## @return: 结果以echo方式返回 55 | function strendwith() 56 | { 57 | if [[ "${1%$2}" = "$1" ]]; then 58 | echo 0 59 | else 60 | echo 1 61 | fi 62 | } 63 | ## @function: . 64 | ## @note: 按空格分隔没有意义, 需要指定显式字符. 65 | function strsplit() 66 | { 67 | : 68 | } 69 | 70 | ## @function 将目标字符串$1中指定内容a替换内容b. 71 | ## $1: 目标字符串 72 | ## $2: 待被替换的内容a 73 | ## $3: 用于替换的内容b 74 | ## $4: 是否全局替换, 如果不是, 则只替换$1中第一个$2. 75 | ## 如果需填true(其余参数无效), 默认为否. 76 | ## @return: 结果以echo方式返回 77 | function strreplace() 78 | { 79 | if [[ "$4" = "true" ]]; then 80 | echo ${1//$2/$3} 81 | else 82 | echo ${1/$2/$3} 83 | fi 84 | } 85 | 86 | ## @function: 判断字符串$1与$2是否相等 87 | ## @return: 结果以echo形式返回 88 | function strequal() 89 | { 90 | if [[ $1 == $2 ]]; then 91 | echo 1 92 | else 93 | echo 0 94 | fi 95 | } 96 | 97 | ## @note: MacOS下的bash可能会出错: bad substitution 98 | function strupper() 99 | { 100 | echo ${1^^} 101 | } 102 | 103 | ## @note: MacOS下的bash可能会出错: bad substitution 104 | function strlower() 105 | { 106 | echo ${1,,} 107 | } 108 | 109 | ## @function: 字符串切片, 不支持倒数截取 110 | ## $1: 待截取的字符串 111 | ## $2: 开始位置start(可为负数, 倒数计数) 112 | ## $3: 结束位置end(可为负数, 倒数计数). 113 | ## 由于是左闭右开区间, 所以$3最大可以为$1的长度值本身. 114 | ## 可为空, 为空时表示截取到$1结尾. 115 | function strslice() 116 | { 117 | local slen=$(strlen "$1") 118 | local start=$2 119 | local end=${3:-$slen} 120 | ## 如果结束位置超出了$1的长度, 则抛出异常 121 | if ((end > slen)); then 122 | ## 抛出异常, 同时返回空字符串 123 | echo 'invalid end param' 1>&2 124 | return 1 125 | fi 126 | 127 | if ((start < 0)); then 128 | ## let 简单计算命令 129 | let start=$slen+$start 130 | fi 131 | if ((end < 0)); then 132 | ## let 简单计算命令 133 | let end=$slen+$end 134 | fi 135 | ## 如果起始位置>结束位置, 则抛出异常 136 | if ((start > end)); then 137 | ## 抛出异常 138 | return 1 139 | fi 140 | local len=$end-$start 141 | echo ${1:start:len} 142 | } 143 | 144 | ## @function: 字符串切片, 不支持倒数截取 145 | ## $1: 待截取的字符串 146 | ## $2: 从开始计数截取的位置start 147 | ## $3: 截取的长度len(len可以超过str的长度) 148 | function strsub() 149 | { 150 | ## 第一个参数为变量时不可以带$符号, 151 | ## 第2,3个参数必须带, 否则会被当成数值 152 | if [[ $3 != '' ]]; then 153 | echo ${1:$2:$3} 154 | else 155 | echo ${1:$2} 156 | fi 157 | } 158 | 159 | ## @function: 字符串反向切片(string reverse sub), 倒数截取 160 | ## $1: 待截取的字符串 161 | ## $2: 从末尾计数截取的位置start 162 | ## $3: 截取的长度len(len可以超过str的长度) 163 | function strrsub() 164 | { 165 | ## 第一个参数为变量时不可以带$符号, 166 | ## 第2,3个参数必须带, 否则会被当成数值 167 | if [[ $3 != '' ]]; then 168 | echo ${1:0-$2:$3} 169 | else 170 | echo ${1:0-$2} 171 | fi 172 | } 173 | -------------------------------------------------------------------------------- /libs/url.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # urlencode 4 | ## @function: 转义目标url $1中的非法字符, 5 | ## 功能等同于js中的encodeURI, 6 | ## python中的urllib.parse.quote 7 | ## $1: 目标url字符串. 8 | ## @return: 结果以echo形式返回 9 | function urlencode() 10 | { 11 | old_lc_collate=$LC_COLLATE 12 | LC_COLLATE=en_US.utf8 13 | ## 取字符串长度 14 | local length="${#1}" 15 | ## 循环遍历其中的每个字符, 对部分ascii字符区别对待. 16 | local result='' 17 | for (( i = 0; i < length; i++ )); do 18 | ## 获取字符串中第i个字符 19 | local c="${1:i:1}" 20 | local _str='' 21 | case $c in 22 | ## 不转义如下字符 23 | [a-zA-Z0-9.~_-]) 24 | _str=$(echo -n "$c") 25 | ;; 26 | ## 其他字符都转义 27 | ## printf不能将中文字符转换成16进制, 所以这里仍然使用xxd命令 28 | ## *) printf '%%%02X' "'$c" ;; 29 | *) 30 | ## sed将字符串中每两个字符前加上%, 如: aabb->%aa%bb 31 | _str=$(echo -n "$c" | xxd -plain | sed 's/\(..\)/%\1/g') 32 | ;; 33 | esac 34 | result=${result}${_str} ## 字符串拼接 35 | done 36 | LC_COLLATE=$old_lc_collate 37 | echo $result 38 | } 39 | 40 | ## @function: 解码%xx形式的字符串$1 41 | ## @return: 结果以echo形式返回 42 | function urldecode() 43 | { 44 | ## 这句是借助{}将$1中传入的字符串中的加号+转换成空格, 有什么意义吗? 45 | ## local url_encoded="${1//+/ }" 46 | 47 | ## 将%xx转换成\xxx, 直接打印. 48 | ## 进制为%b, 二进制直接输出, 可以自动组合成中文. 49 | ## printf与echo都可以 50 | ## printf '%b' "${1//%/\\x}" 51 | echo -en "${1//%/\\x}" 52 | } 53 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # bash-libs 2 | 3 | 1. [日志分级, 彩色打印](./sample/logger_doc.md) 4 | 2. [字符串操作](./sample/str_doc.md) 5 | - `strlen $1`: 返回字符串$1的长度, 返回数值. 6 | - `strcontains $1 $2`: 判断字符串$1是否包含$2的子串, 是则返回1, 否则返回0. 7 | - `strstartwith $1 $2`: 判断字符串$1是否以$2为起始, 是则返回1, 否则返回0. 8 | - `strendwith $1 $2`: 判断字符串$1是否以$2为结尾, 是则返回1, 否则返回0. 9 | - `strupper $1`: 将字符串$1中的小写字母转换为大写, 返回转换后的字符串. 10 | - `strlower $1`: 将字符串$1中的大写字母转换为小写, 返回转换后的字符串. 11 | - `strslice $1 $2 $3`: 截取字符串$1中索引区间为`[$2, $3)`的子串并返回, 行为模式与python中的`str[1:5]`相似. 12 | - `strsub $1 $2 $3`: 截取字符串$1中从$2开始长度为$3的子串并返回. 13 | - `strrsub $1 $2 $3`: 截取字符串$1中从$2开始长度为$3的子串并返回, 但$2是从末尾开始计数的. 14 | -------------------------------------------------------------------------------- /sample/bash编程规范.md: -------------------------------------------------------------------------------- 1 | # bash编程规范 2 | 3 | ## 关于注释 4 | 5 | 短注释仍然使用`#`, 跨行注释可以借助冒号`:`与引号`'`完成. 6 | 7 | ```bash 8 | : ' 9 | ## 注意冒号后有一个空格 10 | ## crontab设置 11 | * * * * * source /root/.ssh/ssh_tunnel_keepalive.sh && check_ssh_proc 12 | */2 * * * * source /root/.ssh/ssh_tunnel_keepalive.sh && check_ssh_tunnel 13 | ' 14 | var=123 15 | ``` 16 | -------------------------------------------------------------------------------- /sample/http_doc.md: -------------------------------------------------------------------------------- 1 | # http_doc 2 | 3 | 参考文章 4 | 5 | 1. [Minimal web server using netcat](https://stackoverflow.com/questions/16640054/minimal-web-server-using-netcat) 6 | 2. [Ubuntu: Simulating a Web Server using Netcat](https://fabianlee.org/2016/09/26/ubuntu-simulating-a-web-server-using-netcat/) 7 | 8 | -------------------------------------------------------------------------------- /sample/logger_doc.md: -------------------------------------------------------------------------------- 1 | # logger_doc 2 | 3 | 参考文章 4 | 5 | 1. [bash:tip_colors_and_formatting](https://misc.flogisoft.com/bash/tip_colors_and_formatting) 6 | - bash shell下的颜色显示设置 7 | 8 | 实现了日志的彩色打印和分级打印, 使用方法见[logger_test.sh](./logger_test.sh). 9 | 10 | ![](../assets/logger-01.png) 11 | 12 | `log_XXX`用于输出到文件, `clog_XXX(color log)`可用于终端打印, 因为后者打印的字符输出到文件会得到乱码. 13 | 14 | ## 基础知识 15 | 16 | bash的颜色打印应该是按照输出字符的特定前缀进行捕获的, 完整的颜色格式如下 17 | 18 | ``` 19 | \033[显示方式;前景色;背景色m 20 | ``` 21 | 22 | 显示方式, 前景色与背景色都为数值类型. 其中分号是为了分隔中文, 实际是不应存在的. 23 | 24 | **显示方式取值:** 25 | 26 | - `0`: 终端默认设置; 27 | - `1`: 高亮显示; 28 | - `4`: 使用下划线; 29 | - `5`: 闪烁; 30 | - `7`: 反白显示; 31 | - `8`: 不可见; 32 | 33 | **前景色取值:** 34 | 35 | - `30`: 黑色(black); 36 | - `31`: 红色(red); 37 | - `32`: 绿色(green); 38 | - `33`: 黄色(yellow); 39 | - `34`: 蓝色(blue); 40 | - `35`: 紫红(purple); 41 | - `36`: 青色(cyan); 42 | - `37`: 白色(white); 43 | 44 | **背景色取值:** 45 | 46 | - `40`: 黑色(black); 47 | - `41`: 红色(red); 48 | - `42`: 绿色(green); 49 | - `43`: 黄色(yellow); 50 | - `44`: 蓝色(blue); 51 | - `45`: 紫红(purple); 52 | - `46`: 青色(cyan); 53 | - `47`: 白色(white); 54 | 55 | ## 示例 56 | 57 | echo的`-e`选项可以避免转义目标字符中的反斜线. 58 | 59 | 在实验时, 我发现显示模式, 前景色与背景色的覆盖方式不太一样, 不过目前不想深究. 只要知道在颜色打印完成后, 需要使用`\033[0m`将颜色设置关闭, 否则会出现下面的情况. 60 | 61 | ``` 62 | echo -e '\033[32m' 63 | echo '之后的打印信息都会是这种效果' 64 | ``` 65 | 66 | ![](../assets/logger-11.png) 67 | 68 | ``` 69 | echo -e '\033[0m' 70 | echo '这样才能恢复正常' 71 | ``` 72 | 73 | ![](../assets/logger-12.png) 74 | -------------------------------------------------------------------------------- /sample/logger_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source $(cd $(dirname $0) && pwd)/../libs/logger.sh 4 | 5 | log_info '默认日志等级为 INFO' 6 | 7 | log_debug '这是一条 DEBUG 日志' ## 不显示 8 | log_info '这是一条 INFO 日志' 9 | log_warn '这是一条 WARN 日志' 10 | log_error '这是一条 ERROR 日志' 11 | log_success '这是一条 SUCCESS 信息' 12 | 13 | clog_debug '这是一条 DEBUG 日志' ## 不显示 14 | clog_info '这是一条 INFO 日志' 15 | clog_warn '这是一条 WARN 日志' 16 | clog_error '这是一条 ERROR 日志' 17 | clog_success '这是一条 SUCCESS 信息' 18 | 19 | print '' 20 | clog_info '修改日志等级为 DEBUG' 21 | __LOGGER_LOG_LEVEL__=$__LOGGER_LEVEL_DEBUG__ 22 | log_debug '这是一条 DEBUG 日志' ## 此时会显示 23 | clog_debug '这是一条 DEBUG 日志' ## 此时会显示 24 | 25 | print '' 26 | print '普通信息打印, 颜色打印函数与日志等级无关' 27 | print_blue '蓝色信息打印' 28 | print_green '绿色信息打印' 29 | print_yellow '绿色信息打印' 30 | print_green '绿色信息打印' 31 | print_red '红色信息打印' 32 | -------------------------------------------------------------------------------- /sample/proc_doc.md: -------------------------------------------------------------------------------- 1 | # proc_doc 2 | 3 | bash的后台执行其实还是通过`&`实现的, 所以本质上是多进程而非多线程. 4 | 5 | 另外通过mkfifo作为管道可以实现多进程间相互通信 -------------------------------------------------------------------------------- /sample/str_doc.md: -------------------------------------------------------------------------------- 1 | # str_doc 2 | 3 | ## 已实现的函数 4 | 5 | - `strlen $1`: 返回字符串$1的长度, 返回数值. 6 | - `strcontains $1 $2`: 判断字符串$1是否包含$2的子串, 是则返回1, 否则返回0. 7 | - `strstartwith $1 $2`: 判断字符串$1是否以$2为起始, 是则返回1, 否则返回0. 8 | - `strendwith $1 $2`: 判断字符串$1是否以$2为结尾, 是则返回1, 否则返回0. 9 | - `strupper $1`: 将字符串$1中的小写字母转换为大写, 返回转换后的字符串. 10 | - `strlower $1`: 将字符串$1中的大写字母转换为小写, 返回转换后的字符串. 11 | - `strslice $1 $2 $3`: 截取字符串$1中索引区间为`[$2, $3)`的子串并返回, 行为模式与python中的`str[1:5]`相似. 12 | - `strsub $1 $2 $3`: 截取字符串$1中从$2开始长度为$3的子串并返回. 13 | - `strrsub $1 $2 $3`: 截取字符串$1中从$2开始长度为$3的子串并返回, 但$2是从末尾开始计数的. 14 | 15 | 使用示例见[str_test.sh](./str_test.sh). 16 | 17 | ## 所遇问题 18 | 19 | 双引号包裹下的感叹号会有问题, 这是bash内置的机制, 与str函数没有关系. 20 | 21 | ```console 22 | $ str="!" 23 | bash: !: event not found 24 | ``` 25 | -------------------------------------------------------------------------------- /sample/str_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source $(cd $(dirname $0) && pwd)/../libs/str.sh 4 | 5 | ######################################################### 6 | ## strlen 7 | 8 | strlen '1q2w3e4r5t6y7u8i9o0p' ## 10 9 | strlen '!@#$%^&*()_+-=[]{}' ## 18 10 | strlen '""' ## 2 11 | strlen "''" ## 2 12 | 13 | ######################################################### 14 | ## strcontains 15 | 16 | strcontains abcd ab ## 1 17 | strcontains abcd abd ## 0 18 | strcontains "hello world" "hello" ## 1 19 | strcontains "hello world" "hello w" ## 1 20 | strcontains "hello world" "hello x" ## 0 21 | 22 | ######################################################### 23 | ## strstartwith 24 | 25 | strstartwith abcd a ## 1 26 | strstartwith abcd ab ## 1 27 | strstartwith abcd b ## 0 28 | strstartwith abcd bc ## 0 29 | strstartwith "hello world" "hello" ## 1 30 | strstartwith "hello world" " hello" ## 0 31 | 32 | ######################################################### 33 | ## strendwith 34 | 35 | strendwith abcd d ## 1 36 | strendwith abcd cd ## 1 37 | strendwith abcd a ## 0 38 | strendwith abcd ab ## 0 39 | strendwith "hello world" "world" ## 1 40 | strendwith "hello world" "world " ## 0 41 | 42 | ######################################################### 43 | ## strupper 44 | 45 | strupper abcd ## ABCD 46 | strupper abCD ## ABCD 47 | strupper "hello world" ## HELLO WORLD 48 | strupper "Hello World" ## HELLO WORLD 49 | strupper "Hello World@#$%^&*()_+-=[]{},.<>/?" ## HELLO WORLD@#$%^&*()_+-=[]{},.<>/? 50 | strupper "世界 你好" ## 世界 你好 51 | ## 注意: 双引号包裹的英文感叹号!会被转义, 但这并不是脚本问题, 而bash本身的机制. 52 | strupper "Hello World!" ## HELLO WORLD 53 | strupper 'Hello World!' ## HELLO WORLD! 54 | 55 | ######################################################### 56 | ## strlower 57 | 58 | strlower ABCD ## abcd 59 | strlower abCD ## abcd 60 | 61 | ######################################################### 62 | ## strslice 63 | strslice 'hello world' 0 5 ## hello 64 | strslice 'hello world' 0 11 ## hello world 65 | strslice 'hello world' 0 -3 ## hello wo 66 | strslice 'hello world' -5 -3 ## wo 67 | 68 | ######################################################### 69 | ## strsub 70 | 71 | strsub 'hello world' 0 5 ## hello 72 | ######################################################### 73 | ## strrsub 74 | 75 | strrsub 'hello world' 5 5 ## world 76 | 77 | ######################################################### 78 | ## strreplace 79 | echo ================== strreplace 80 | strreplace '1 2 3' ' ' ',' ## 1,2 3 81 | strreplace '1 2 3' ' ' ',' 'true' ## 1,2,3 82 | -------------------------------------------------------------------------------- /sample/url_doc.md: -------------------------------------------------------------------------------- 1 | # url_doc 2 | 3 | 参考文章 4 | 5 | 1. [shell 下 urlencode/urldecode 编码/解码的几种方法](https://blog.csdn.net/carlostyq/article/details/7928610) 6 | - 关于urlencode/urldecode必要性的解释很准确 7 | - 借助`xxd`和`od`命令实现shell版本的encode/decode方法. 8 | 2. [github gist urlencode/urldecode](https://gist.github.com/cdown/1163649) 9 | 10 | 我们在浏览器中访问一个路径中包含中文字符的url时, 从地址栏复制出地址会发现其中的中文字符是被转义过的. 如果使用`curl`直接访问包含中文(不只是中文, 还有其它的一些特殊字符等)的url可能会出错, 我们需要一事先将url进行编码. 11 | 12 | js, python等高级语言都有对应的urlencode/urldecode函数, 用于转义url中的非法字符. 13 | 14 | ```js 15 | encodeURI('good 中国!') // "good%20%E4%B8%AD%E5%9B%BD!" 16 | ``` 17 | 18 | ```py 19 | from urllib.parse import quote 20 | quote('good 中国!') ## 'good%20%E4%B8%AD%E5%9B%BD%21' 21 | ``` 22 | 23 | > js与py的encode函数有些许差别, js的3个编码函数`escape`, `encodeURI`和`encodeURIComponent`没有一个是与python中`quote`一致的. 24 | 25 | 而shell中是没有提供类似的命令, 但是 26 | 27 | 参考文章1中的方案是直接借助`xxd`或`od`命令模拟`encode`/`decode`, 但是这样做的缺陷是, ta们只是单纯的进行进制转换(转换成16进制), 无法分辨哪些是需要转换的, 哪些是不需要的(比如26个英文字母在url中就是合法字符). 28 | 29 | ```bash 30 | echo -n 'good 中国' | xxd -plain | sed 's/\(..\)/%\1/g' ## %67%6f%6f%64%20%e4%b8%ad%e5%9b%bd%21 31 | ``` 32 | 33 | > `sed`的部分是将每2个16进制字符(0-F)前添加上百分号`%`, 如`中`的16进制表示`e4b8ad`->`%e4%b8%ad`. 34 | 35 | 这样是不行的. 36 | 37 | 参考文章2中给出了`encode`更为细致的实现方法, 即循环转义每个字符为16进制. 但由于ta借助的是`printf`命令, 只能转换单个char字符为16进制, 但是中文字符是由多个char字符组合而成的, 这样转换出来的字符是有问题的, 所以仍然需要`xxd`的帮助. 38 | 39 | ------ 40 | 41 | 另外, 貌似不同语言对于url中哪些字符需要编码的表现并不相同, 这里我们只暂时这么用吧, 以后再更新. 42 | -------------------------------------------------------------------------------- /sample/url_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source $(cd $(dirname $0) && pwd)/../libs/url.sh 4 | 5 | str='good 中国!' 6 | echo "原始字符串: ${str}" ## good 中国! 7 | encoded_str=$(urlencode "$str") 8 | echo "编码字符串: ${encoded_str}" ## good%20%e4%b8%ad%e5%9b%bd%21 9 | decoded_str=$(urldecode "$encoded_str") 10 | echo "解码字符串: ${decoded_str}" ## good 中国! 11 | --------------------------------------------------------------------------------