纯sh圣经-POSIX sh外部进程的替代方案

2020-10-20 01:42:33

本书的目标是记录仅使用内置POSIX sh功能执行各种任务的常见和不太知名的方法。使用这本“圣经”中的代码片段可以帮助从脚本中移除不需要的依赖关系,并且在大多数情况下可以使脚本运行得更快。在开发KiSS Linux和其他较小的项目时,我偶然发现了这些技巧,并发现了一些技巧。

看到一些描述错误、错误或完全错误的东西吗?打开问题或发送拉式请求。如果圣经遗漏了什么,打开一个问题,就会找到解决方案。

这是sed、awk、perl和其他工具的替代工具。下面的函数通过查找所有前导和尾随空格并将其从字符串的开头和结尾处删除来实现。

TRIM_STRING(){#用法:TRIM_STRING";示例字符串";#删除所有前导空格。#';${1%%[![:space:]]*}';:删除除前导空格以外的所有内容。#';${1#${XXX}}';:删除字符串开头的空格。Trim=${1#${1%%[![:space:]]*}}#删除所有尾随空格。#';${trim##*[![:space:]]}';:除去尾随空格以外的所有内容。#';${trim#${XXX}}';:从字符串末尾删除空格。Trim=${trim%${trim##*[![:space:]]}}printf';%s\n';";$trim";}。

这是sed、awk、perl和其他工具的替代工具。下面的函数通过滥用拆分单词来创建没有前导/尾随空格和截断空格的新字符串。

#shellcheck DISABLE=SC2086,SC2048 TRIM_ALL(){#用法:TRIM_ALL";示例字符串";#DISABLE GLOBING以确保下面的分词是安全的。Set-f#将参数列表设置为单词拆分的字符串。#这将删除所有前导/尾随空格,并将#多个空格的所有实例减少为一个(";";-&>;";";)。Set--$*#将参数列表打印为字符串。Printf';%s\n';";$*";#重新启用全局绑定。设置+f}。

$Trim_all";Hello,World";Hello,World$name=";John Black是我的名字。";$TRIM_ALL";$NAME";约翰·布莱克是我的名字。

在*SUB_STRIN1*)#执行任务;;*SUB_STRIN2*)#执行其他任务;;*)#其他;;esac中的case$var;;esac

SUB_STRIN1*)中的case$var#执行任务;;SUB_String2*)#执行其他任务;;*)#Else;;esac。

*SUB_STRIN1)#执行任务;;*SUB_STRIN2)#执行其他任务;;*)#ELSE;;ESAC中的case$var。

Split(){#禁用全局绑定。#这样可以确保分词是安全的。Set-f#存储';IFS';的当前值,以便我们#可以在以后恢复它。Old_ifs=$IFS#将字段分隔符更改为我们重新#拆分的位置。IFS=$2#在每个#次出现';$2';时创建一个参数列表拆分。##禁用此功能是安全的,因为它只是警告#分词,这是我们预期的行为。#shellcheck Disable=2086 set--$1#在各自的行上打印每个列表值。Printf';%s\n';";$@";#还原';IFS';的值。Ifs=$old_ifs#重新启用全局绑定。设置+f}。

TRIM_QUOTES(){#用法:TRIM_QUOTES";STRING";#禁用全局绑定。#这使得下面的分词是安全的。Set-f#存储';IFS';的当前值,以便我们#可以在以后恢复它。Old_ifs=$IFS#将IFS#设置为[";';]。IFS=\";\';#创建参数列表,在[";';]处拆分#字符串。##禁用此外壳检查错误,因为它只警告我们预期的分词问题。#shellcheck DISABLE=2086将--$1#Set';IFS';设置为空白,以删除[";';]留下的#空格。Ifs=#打印不带引号的字符串。Printf';%s\n';";$*";#还原';IFS';的值。Ifs=$old_ifs#重新启用全局绑定。设置+f}。

#Setting';IFS';告诉';Read';在哪里拆分字符串。而IFS==';=';读取-r键val;do#跳过包含注释的行。#(以';#';开头的行)。[";${key##\#*}";]||Continue#';$key';存储密钥。#';$val';存储值。Printf';%s:%s\n';";$key";";$val";#或者用以下#替换';printf';用';$val';值填充称为';$key';的变量。##注意:我将通过检查来扩展这一点,以确保';key';是一个有效的变量名。#export";$key=$val";##错误处理示例:#export";$key=$val";2>;/dev/null||#printf';警告%s不是有效的变量名\n';";$key";完成<;";文件";

Head(){#用法:head";n";";file";while IFS=read-r line;do printf';%s\n';";$line";i=$((i+1))[";$i";=";$1";]&;&;Return<;";$2";循环中使用的#';read';如果不包含#a换行符,而是包含EOF,则会跳过文件的最后一行。##最后一行迭代将被跳过,因为当';Read';#命中EOF时,它将以';1';退出。';READ';但是,#仍然填充变量。##这可确保始终打印最后一行#(如果适用)。[-n";$line";]&;&;printf%s";$line";}。

LINES(){#用法:LINES";FILE";#';||[-n";$LINE";]';:这样可以确保循环中仍对以EOL结尾的行#而不是换行行进行#操作。当##';READ';看到EOL和#时,它会退出';,没有添加测试,则该行不会将#发送到循环。而IFS=读取-r行||[-n";$line";];DO LINES=$((LINES+1))Done<;";$1";printf';%s\n';";$LINES";}。

这是通过将glob的输出传递给函数,然后计算参数的数量来实现的。

Count(){#用法:count/path/to/dir/*#count/path/to/dir/*/[-e";$1";]\&;&;&;printf';%s\n';";$#";\||printf';%s\n';0}。

#计数目录$count~/downloads/*232#计数目录$count~/downloads/*/45#统计目录$count~/Pictures/*.jpg64中的所有jpg文件。

Dirname(){#用法:dirname";path";#if';$1';is null set';dir';to';.';,Else';$1';。Dir=${1:-.}#从#字符串末尾去掉所有尾随正斜杠';/';。##";${dir##*[!/]}";:从字符串开头删除所有非正斜杠#,只留下#尾部斜杠。#";${dir%%";${}";}";:从原始字符串的#末尾删除上述#替换的结果(一串正斜杠)。Dir=${dir%%";${dir##*[!/]}";}#如果变量*不*包含任何正斜杠#将其值设置为';.';。[";${dir#**/*}";]&;&;dir=。#删除*最后一个正斜杠';/';之后的所有*内容。Dir=${dir%/*}#再次删除字符串末尾#中的所有尾随正斜杠';/';(见上文)。Dir=${dir%%";${dir##*[!/]}";}#打印结果字符串,如果为空,则#print';/';。Printf';%s\n';";${dir:-/}";}。

Basename(){#用法:basename";path";[";Suffix";]#从#字符串末尾删除所有尾随正斜杠';/';。##";${1##*[!/]}";:从字符串开头删除所有非正斜杠#,只留下#尾部斜杠。#";${1%%";${}";}:从原始字符串的#末尾删除上述#替换的结果(一串正斜杠)。Dir=${1%${1##*[!/]}}#删除最后一个正斜杠';/';之前的所有内容。Dir=${dir##*/}#如果向函数传递了后缀,请将其从结果字符串末尾的#中删除。Dir=${dir%";$2";}#打印结果字符串,如果为空,则#print';/';。Printf';%s\n';";${dir:-/}";}。

可替代SEQ,仅适用于较小的静态数字范围。数字列表还可以替换为单词、变量等的列表。

#从0到10循环。对于0 1 2 3 4 5 6 7 8 9 10;中的I,执行打印操作';%s\n';";$I";完成。

而IFS=读取-r行||[-n";$line";];执行打印f';%s\n';";$line";完成<;";文件";

警告:当glob不匹配任何内容(空目录或没有匹配的文件)时,该变量将包含未展开的glob。要避免使用未展开的GLOB,请使用适当的文件条件检查变量中包含的文件是否存在。请注意,符号链接已解析。

#贪婪的例子。对于*;DO[-e";$FILE";]||[-L";$FILE";]||继续打印目录中的#个PNG文件。对于~/Pictures/*.png;中的文件,执行[-f";$FILE";]||继续打印f';%s\n';";$FILE";Done#迭代目录。对于~/Downloads/*/中的目录,执行[-d";$dir";]||继续打印';%s\n';";$dir";完成。

与人们普遍认为的相反,利用原始转义序列是没有问题的。使用tput提取相同的ANSI序列,就像手动打印一样。更糟糕的是,tput实际上不是可移植的。有许多tput变体,每个都有不同的命令和语法(在FreeBSD系统上尝试tput setaf 3)。原始序列没问题。

#如果var2大于var,则将var的值设置为var2。#';var2>;var';:要测试的条件。#';?Var2';:如果测试成功。#';:var';:如果测试失败。var=$((var 2&>var?Var 2:var))。

IS_FLOAT(){#用法:IS_FLOAT";number";#测试检查输入是否包含#a';.';。这会过滤出整数。[-z";${1##*.。*}";]&;&;printf%f";$1";>;/dev/null 2>;&;1}。

陷阱允许脚本对各种信号执行代码。在pxltrm(用bash编写的像素艺术编辑器)中,陷阱用于在调整窗口大小时重新绘制用户界面。另一个用例是在脚本退出时清理临时文件。

应在脚本开头附近添加陷阱,以便也能捕获任何早期错误。

#在脚本退出时清除屏幕。陷阱';printf\\033[2J\\033[H\\033[m&#;exit#]在脚本退出时运行函数。#';CLEAN_UP';是函数的名称。陷阱清理出口。

谢谢你的阅读!如果这本“圣经”以任何方式帮助了你,而你又想回馈社会,那就考虑捐献吧。捐款给了我时间让它成为最好的资源。不能捐献吗?这是好的,启动回购,并与您的朋友分享!