「Rust」- 场景及方案

静态编译
“cannot produce proc-macro for `crate` as the target `x86_64-unknown-linux-gnu` does not support these crate types” with +crt-static rust – How to generate statically linked executables? – Stack Overflow

// 通过命令行专递参数构建

RUSTFLAGS=”-C target-feature=+crt-static” cargo install –jobs 2 –path . –target x86_64-unknown-linux-gnu

// 或者,通过 Cargo.toml 文件:

[target.x86_64-pc-windows-msvc]
rustflags = [“-C”, “target-feature=+crt-static”]
…[……]

READ MORE

「SHELL-SCRIPTING」- 学习指南

研究对象
Shell Scripting,脚本编程
研究结果
1)理论:掌握 Shell 脚本的编写方法,及与 Shell 编程有关的内容; 2)实践:能够进行 Shell 编写,并且编写出可移植性高的脚本是个非常重要的目标;
研究方法
信息采集
教育培训:WIP
书籍文章: 1)《Linux Shell 脚本攻略(第 2 版)》
官方文档: 1)https://www.gnu.org/software/bash/manual/bash.html
博客文章:WIP
制定路线
针对 Bash 的学习,我们将沿用 Bash Reference Manual 的结构,逐步深入学习;
补充说明
# 08/20/2019 起初这个分类是为 UNIX Shell 准备的,现在开始也准备加入部分 PowerShell 相关的技术;[……]

READ MORE

「SHELL-SCRIPTING」- 语法

关于 Shell 编程语言的学习。既然是编程语言的学习,自然也就逃不开编程语言的那一套:变量,数组,类型函数等等概念;[……]

READ MORE

「ANSI escape code」- 终端转义序列

TODO ANSI Color Code True Colour (16 million colours) support in various terminal applications and terminals
\e[31m \033[31m \e[0m \033[0m
移动光标的转义序列
Cursor Movement

– Position the Cursor:
\033[<L>;<C>H
Or
\033[<L>;<C>f
puts the cursor at line L and column C.
– Move the cursor up N lines:
\033[<N>A
– Move the cursor down N lines:
\033[<N>B
– Move the cursor forward N columns:
\033[<N>C
– Move the cursor backward N columns:
\033[<N>D

– Clear the screen, move to (0,0):
\033[2J
– Erase to end of line:
\033[K

– Save cursor position:
\033[s
– Restore cursor position:
\033[u

实现进度条

#!/bin/bash

echo -n ‘——————————————‘
echo -n -e “\r” # 移动光标到行首

while true;
do
echo -n -e ‘\033[1C’ # 光标向后移动一位
echo -n -e ‘\b’ # 删簇一个字符
echo -n ‘#’ # 打印一个井号
sleep 0.5 # 休眠 500ms
done

参考文献
Wikipedia/ANSI escape code Bash tips: Colors and formatt[……]

READ MORE

「Linux」- 颜色化输出

问题描述
在终端中,我们经常查看日志输出(不管是自己的 Shell 脚本,还是运行其他程序),以了解程序执行情况。
但是,所有的终端日志颜色都是相同的(通常默认都是白色字体),
该笔记将记录:将终端输出变成彩色的方法
解决方案
方法一、ANSI escape code – 最古老的方法
使用 ANSI escape code 是最古老的方法:

# echo -e “\033[31;1;4mHello\033[0m”
Hello

该命令将输出带下划线的红色 Hello 字符串
方法二、grc

# grc tail -f /var/log/syslog

该命令将高亮 syslog 日志输出,通过配置文件可以进行更多控制
其他工具
colortail GitHub – joakim666/colortail: Like the tail command line utility but with colors
colorex GitHub – Scopart/colorex: A python script to display log files with colors.
colout GitHub – nojhan/colout: Color text streams with a polished command line interface
TxtStyle GitHub – armandino/TxtStyle: Command-line tool for colorizing console output and log files based on regular expressions
rainbow GitHub – nicoulaj/rainbow: Colorize commands output or STDIN using patterns.
highlight André Simon – Startseite
lolcat GitHub – busyloop/lolcat: Rainbows and unicorns!
参考文献
terminal – Output in color – Bash – Unix & Linux Stack Exchange GitHub – garabik/grc: generic colouriser[……]

READ MORE

「Shell」- 2.Environment Setup

常见 Shell 整理
Wikipedia/Comparison of command shells
sh – Borune shell
bash – Bourne Again Shell
dash – Debian Almquist Shell
以POSIX兼容性为目标。
Z shell(zsh)
Kornshell(ksh)
pdksh是ksh93的自由软件版本。
pdksh 现在是 mksh(http://mirbsd.de/mksh%EF%BC%89%E3%80%82
C shell(csh)
Tenex C shell(tcsh)
环境安装
在 Linux distro 中,已经携带 Shell 环境,通常不需要自行安装,除非想要使用其他类型的 Shell 环境。

# Bash
apt-get install -y bash[……]

READ MORE

「Shell」- 快速入门及简单示例

定义变量
变量转义
这是别人在群里问到的一个问题。看如下命令:

ssh localhost “/bin/cat > /tmp/tmp << eof
\\\$demo
eof”

上述命令生成的/tmp/tmp文件的内容是$demo,为什么?首先,传给SSH的命令在双引号中,所以Bash先解析一次,但是它解析了”\\“和”\$“两个组合。也就是说,SSH拿到手的时候,命令已经变成”\$name“。即:

/bin/cat > /tmp/tmp << eof
\$demo
eof

那么,写入文件的自然就是”$name“字符串。
换句话说,下面的写法是等效的:

ssh localhost ‘/bin/cat > /tmp/tmp << eof
\$dddd1
eof

变量引用
定义了一个SHELL函数:

ddPATH=”-cp /mnt/demo”
debug=com.k4nz.Enter

debug()
{
java $ddPATH “$USER_FLAGS” $debug
}

而USER_FLAGS使用用户自定义的,可能存在,也可能不存在。在执行这个函数的时候会产生如下错误:

Error: Could not find or load main class

我们尝试打印出要执行的命令,所以对函数作出如下修改,加了一个echo命令:

ddPATH=”-cp /mnt/demo”
debug=com.k4nz.Enter

debug()
{
echo java $ddPATH “$USER_FLAGS” $debug
}

该函数的输入如下:

java -cp /mnt/demo com.k4nz.Enter

在命令行里执行这个命令是没有错误,完全可以正常执行这个类,这就见鬼了。
其实,有的时候就是需要非常仔细的观察,问题的关键就在于那个”$USER_FLAGS”,修改成$USER_FLAGS就正常了。为什么?
由于USER_FLAGS未定义,函数里的java $ddPATH “$USER_FLAGS” $debug命令执行前,SHELL会先进行解析,而解析的结果是java -cp /mnt/demo “” com.k4nz.Enter,而echo的结果是java -cp /mnt/demo com.k4nz.Enter,这两个并不等价。而当我们把函数里的命令修改成java $ddPATH $USER_FLAGS $debug后,解析的结果就与echo等价了,这时候也不会出现那[……]

READ MORE

「Shell」- 模块及框架

PowerShell Gallery
Welcome to the PowerShell Gallery
The central repository for sharing and acquiring PowerShell code including PowerShell modules, scripts, and DSC resources.
框架及方法
Shellscript framework make quick bash scripts Bashinator: Bash Shell Script Framework

章节列表
「Shell」- 处理 YAML 文件 「Bash」- type(学习笔记) 「Bash」- 内建命令(学习笔记) 「Shell」- 进程替换(Process substitution) 「Shell」- 使用环境变量,替换在文件中的变量(envsubst) 「Bash」- shift(学习笔记) 「Bash」- 自动补全功能(Bash Completion)[……]

READ MORE

「Bash」- 自动补全功能(Bash Completion)

问题描述
Bash Completion,是个 Bash 特性(其他 Shell 也支持),只需轻点几下 TAB 即可实现复杂的命令行选项提示,而无需我们输出复杂、冗长的命令;
该笔记将记录:在 Bash 中,与自动补全(Bash Completion)有关的内容,以及相关问题处理;
解决方案
在终端下,命令自动补全提示功能(<TAB><TAB>)在 Bash Completion 软件包中;
以 Bash 为例
因为大多数的 Shell 都是差不多的,实现上有很多类似的地方。我们平时主要使用的 Shell 也是 Bash,所以就说说 Bash 吧;
必须指出的是TAB键通常发送 ASCII 的Control-I字符。因为控制字符Control-I和TAB键的 ASCII 值是对应的都是9,所以你在终端中按下TAB键的效果和Ctrl-I的效果是一样的;
而Control-I字符绑定在compete函数上。这一点可以通过bind -p | grep -F ‘\C-i’命令看到。bind和complete都是 Bash 中内建的函数,可以使用help bind和help complete命令查看手册。实际上complete是自动补全的关键,当你去看「GitHub/scop/bash-completion/completions/」中的自动补全脚本的时候,你会发现大量的compete -F调用,后面会介绍 Bash Completion 是什么;
所以,当你按下 TAB 键时,向 Bash 发送了 Control-I 字符,收到该字符后 Bash 执行 complete 函数;
如何扩展 Bash 自动补全
默认的自动补全功能有限,基本上只有命令、路径、目录的补全,但是可以扩展自动补全功能,使其支持命令行选项的扩展;
这个就不介绍如何扩展自动补全,有兴趣可以参考以下两篇文章: 1)An introduction to bash completion: part 1 2)An introduction to bash completion: part 2
一来没有遇到去完善自动补全的必要,二来我们有 Bash Completion 软件包;
关于 Bash Completion 软件
默认的自动补全仅能进行简单的自动补全,比如文件目录路径。该软件包扩展 Bash 的自动补全功能,它能满足我们的大多数需要;
项目地址:scop/bash-completion: Programmable completion functions for bash 安装方法:1)参考源码目录下的 README.md 文件;2)或者直接使用包管理器安装(各个[……]

READ MORE

「Bash」- 内建命令(学习笔记)

history 命令执行的历史记录操作、查看;
kill 用于向job或者进程发送信号。
trap [-lp] [[arg] sigspec …]

The command arg is to be read and executed when the shell receives
signal(s) sigspec. If arg is absent (and there is a single
sigspec) or -, each specified signal is reset to its original dis‐
position (the value it had upon entrance to the shell). If arg is
the null string the signal specified by each sigspec is ignored by
the shell and by the commands it invokes. If arg is not present
and -p has been supplied, then the trap commands associated with
each sigspec are displayed. If no arguments are supplied or if
only -p is given, trap prints the list of commands associated with
each signal. The -l option causes the shell to print a list of
signal names and their corresponding numbers. Each sigspec is
either a signal name defined in <signal.h>, or a signal number.
Signal names are case insensitive and the SIG prefix is optional.

If a sigspec is EXIT (0) the command arg is executed on exit from the shell.

如果sigspec为DEBUG,对于命令、case命令、select命令、命令的每个算术,会在每个简单的命令并且在shell函数中执行的第一个命令之前先执行命令arg(请参见SHELL GRAMMAR章节)。 有关shopt内[……]

READ MORE

「Bash」- shift(学习笔记)

命令语法格式
shift [n]
命令含义
从n+1开始的参数,被对应到$1,而由$#开始到$#-n+1代表的参数会被重置掉。换句简单的话说:shift后面的n是几,那前几个参数就不要了,假装你没有传过。
参数n必须为非负整数,并且小于等于$#;
如果没有指定n,则n默认为1;
如果n > $#,则位置参数不发生改变;
如果n = 0,则参数不会发生改变;
返回状态
如果n > $#,返回的状态值大于0,或者小于0;
正常情况、没有错误,则返回0。
示例

#!/bin/bash

function cmd(){

shift 2
echo $@
}

cmd 1 2 3 4 5 6 7 8
# 该命令输出:3 4 5 6 7 8
# 此时n=2,那前两个参数就不要了。[……]

READ MORE

「Bash」- type(学习笔记)

命令语法格式
type [-aftpP] name [name …]
命令支持的选项及含义
如果没有选项,type会输出每个做为命令的name将会被如何解释。
如下示例:

# type ls cd mkdir
ls is aliased to `ls -a -CF –color=auto’
cd is a shell builtin
mkdir is /bin/mkdir

-t 如果name是别名、shell保留字、函数、内建命令、普通文件(命令程序)则分别打印alias, keyword, function, builtin, file。 如果name没有找到则什么都不打印,且返回码为false。
如下示例:

# type -t ls
alias

# type -t mkdir
file

-p 如果作为命令名指定name,则type会返回会被执行的硬盘文件。 如果type -t name不返回file,则使用-p时什么都不输出。
示例如下:

# type -p readlink
/bin/readlink

# type -t ls
alias
# type -p ls

这里因为ls被定义成别名,所以使用-p时没有任何输出。

-P 即使type -t name没有返回file,也强制到PATH中搜索name。如果命令做了hash,-p与-P打印hash的值,不一定是第一个出现在PATH中的文件。
-a 使用该选项后将会打印所有命名为name的可执行命令。同时包含了别名和函数,但只有在没有使用-p选项的情况下。 当使用-a时,被hashed的命令不会进行输出。
示例如下:

# type -a ls
ls is aliased to `ls -a -CF –color=auto’
ls is /bin/ls

-f 使用该选项后,不查找shell中定义的函数。
命令返回值
如果type找到了命令,则返回true; 如果type没有找到命令,则返false;[……]

READ MORE

「Bash」- umask

命令语法格式
umask [-p] [-S] [mode]
命令简述
设置创建文件时权限的默认掩码。
命令支持的选项及含义
如果没有指定mode,则打印当前的掩码值。
[mode] 权限的掩码。如果mode以数字开头,则被解释为八进制的掩码数字。否则,mode被当作可由chmod(1)接受的符号模式掩码进行解释。
以下的两种示例格式都是合法的:

# umask 022
# umask u=rwx,g=rx,o=rx

但是,umask 022中的022设置的是权限的掩码,而umask u=rwx,g=rx,o=rx中的u=rwx,g=rx,o=rx设置的是默认的权限。
-S 默认不使用-S时,以八进制格式打印掩码值;使用-S后以符号的形式打印出掩码值。
如下示例:

# umask
0022

# umask -S
u=rwx,g=rx,o=rx

-p 如果使用了-p选项,并且没有指定mode,则以可重用为输入的形式进行输出。
如下示例:

# umask -p
umask 0022

# umask -p 022

对于命令umask -p 022没有任何的输出。
命令的返回值
如果mode修改成功或者没有提供参数,则返回0;其他情况返回false;[……]

READ MORE

「Shell」- 处理 JSON 数据

问题描述
我们需要在 Shell 中处理 JSON 数据,比如我们请求某个 HTTP 接口,接口返回 JSON 数据,而我们需要从中提取某个字段。当然,我们可以使用 sed grep awk 这些工具,但是这些工具只能进行简单处理。如果我们想要生成结构化数据,这些工具是不够的。我们需要处理 JSON 的专用工具。
经过 Google 查找 jq(stedolan/jq: Command-line JSON processor),用于处理 JSON 数据的 Shell 命令行工具。
该笔记将记录:在 Shell 中,如何使用 jq 命令处理 JSON 数据,以及常见问题处理。
解决方案
安装命令
通过包管理器安装。很多 Linux 发行版中都带有该工具:

# Ubuntu 18.04 LTS
apt-get install -y jq

或者,使用源码编译安装,详细的安装过程,参考 jq/README.md at master · stedolan/jq 文件。这里简单记录:

git submodule update –init # if building from git to get oniguruma (正则表达式库)
autoreconf -fi # if building from git
./configure –with-oniguruma=builtin
make -j8
make check

常见示例
根据属性值过滤:

jq ‘.result | select(.location==”Stockholm”)’

判断某个 KEY 是否存在。比如,判断在 result 是否包含 .property_history 字段(KEY),存在则取其值:

jq ‘.result | select(.property_history != null) | .property_history’

判断字段的值是否以某个字符串开始:

jq -r ‘.[]|select(.hostname | startswith(“abcd”))’ jjjj.json

# 判断是否包含某个字符串
jq -r ‘.[]|select(.hostname | contains(“abcd”))’ jjjj.json

修改 JSON 内容:

jq ‘.clusters[].name = 1231231 | .users[].name = 123456’ config.js[……]

READ MORE

「Shell」- 进程替换(Process substitution)

什么是进程替换
先看 WIKI 的解释:

In computing, process substitution is a form of inter-process communication that allows the input or output of a command to appear as a file.

在计算中,进程替换是进程间通信的一种形式,允许命令的输入或输出作为文件出现;

进程替换的语法
cmd1 >(cmd2)

将 cmd1 输出发送给 cmd2

cmd1 <(cmd2)

将 cmd2 的输出发送给 cmd1

在这里:>(cmd2)或者<(cmd2)等价于一个内容为 cmd2 输出的文件。这么说可能不明白,请看下面“进程替换的机制”;
进程替换的机制
题外话: 如果你不会英语,你真的会错过很多东西;
进程替换的实现有两种:

在支持 /dev/fd 的系统上(大多数都支持),通过 pipe()系统调用实现。pipe()系统调用会为匿名管道返回一个文件描述符$fd,然后用字符串 /dev/fd/$fd 替换命令行上的>(cmd2)或者<(cmd2);
对于不支持 /dev/fd 的系统上,Bash 使用新临时文件名调用 mkfifo 来创建一个命名管道,然后使用此文件名作为替代;

为了演示所涉及的步骤,思考如下命令:

diff file1 <(sort file2)

shell 的执行步骤如下(对于支持 /dev/fd 的系统):

创建一个新的匿名管道。这个管道可以通过像 /dev/fd/63 这样的东西访问;你可以用echo <(true)命令看到它;
在后台执行替代命令(当前为 sort file2),将输出输送到匿名管道;
执行主命令,使用匿名管道的路径替换替带命令。在这个例子中,完整的命令可能扩展为:diff file1 /dev/fd/63
当执行结束时,关闭匿名管道;

对于命名管道(不支持 /dev/fd 的系统),唯一不同的地方在于管道的创建和删除:使用 mkfifo 创建;使用 unlink 删除。其他方面一样的;
进程替换的示例

#!/bin/sh

echo <(ls)

# 输出:
# /dev/fd/63

对于cmd1 >(cmd2),当 Bash 在执行进程替换的时候,Bash 会将 cmd2 的[……]

READ MORE

「Shell」- 处理 YAML 文件

yq (GitHub/kislyuk/yq) ⇒ Python
项目地址:kislyuk/yq: Command-line YAML and XML processor – jq wrapper for YAML/XML documents 官方文档:https://kislyuk.github.io/yq/
YAML ⇒ JSON,用于将 YAML 转为 JSON 的工具。该工具是 jq 的封装,所以需要先安装 jq 命令
安装 yq 命令: 1)安装 jq 命令:jq 2)安装 yq 命令:

pip3 install yq

yq (GitHub/mikefarah/yq) ⇒ Go
项目地址:mikefarah/yq: yq is a portable command-line YAML processor
YAML ⇒ JSON,用于将 YAML 转为 JSON 的工具,由 Go 语言开发。
我们没有使用该命令,这里仅作记录。
常用工具
yamllint – A linter for YAML files
该工具用于检查YAML文件的格式是否正确,对YAML进行校验。
执行如下命令即可安装该工具:

# CentOS:
yum install yamllint.noarch

# Debian
apt-get install yamllint

简单的使用示例:

yamllint /path/to/foo.yml

其他内容可以 查看GitHub项目主页、查看命令手册[……]

READ MORE

「Shell」- 常用代码

explainshell.com
解释 Shell 命令的网站; 该站点的源码在 GitHub 中:https://github.com/idank/explainshell
将 Unicode 与 Ascii 互相转化
使用 ascii2uni 和 uni2ascii 在 Unicode 和 Ascii 之间互转;
使用 printf 也可以做到;
执行生成的命令
scripting – Bash: Execute piped lines from stdin – Server Fault
我们会通过 Shell 脚本来生成一些命令,然后再执行这些命令:python example.py | bash
或,更具数据直接组装并执行命令,但有时候这种做法更烦琐;
输入特殊字符
比如输入一个 TAB 键,但是 Bash 中 TAB 用于补全提示。。;
先按下 Ctrl+V,然后在按下 TAB 键;
当 BASH 无响应时
使用 Ctrl+J 组合键;或者输入 reset 内建命令;
修改运行进程的输出
「redirecting output of running background job in bash」 「How to redirect output of an already running process」
脚本优化
Bash script; optimization of processing speed
“The first rule of optimization is: don’t optimize.”
如果数据量大的话还是要换语言(当然,这要你自己控制成本、时间、性能上的平衡)。
倒是有些通用的小办法,可以参考「Bash script; optimization of processing speed」一文中的说明。
你可以自己优化程序,但是你要防止“在优化后,逻辑不如原来清晰、直接”的问题。
参考文献
Read the json data in shell script How to convert \uXXXX unicode to UTF-8 using console tools in *nix[……]

READ MORE

「Shell」- 数组的使用

注意事项
并不是每种 Shell 都支持数组(比如 Bash 支持数组,但是 Dash 不支持数组),为了写出可移植脚本,不建议使用数组。
The Bourne shell or the Unix sh lanuage specification don’t support arrays.
定义 – 如何定义一个数组?
索引数组

# 声明索引数组
declare -a mIndexArray

# 索引数组也可以直接定义:
mIndexArray=(one two three)

关联数组

# 声明关联数组
declare -A mAssociativeArray

# 但是,关联数组不可以直接定义,必须先声明:
declare -A mAssociativeArray
mAssociativeArray=( [foo]=bar [baz]=quux [corge]=grault )

# 如果没有先声明为关联数组,则 mAssociativeArray=( [foo]=bar [baz]=quux [corge]=grault ) 默认为索引数组,并且其中的元素也发生了变化。

赋值 – 如何对数组进行赋值?
对索引数组和关联数组进行赋值方面,两者直接并无太大差异:

mIndexArray[5]=five
mAssociativeArray[five]=five

数组索引也可以是变量:

mAssociativeArray[$var]=value

即使索引是“存在空格的字符串”,也不需要引用:

# 下面三种是等价的
mAssociativeArray[‘key with space’]=value
mAssociativeArray[“key with space”]=value
mAssociativeArray[key with space]=value

也可以使用如下方式,以无需索引的方式向数组中添加元素:

# 如下示例向索引数组mIndexArray中添加了两个元素,但是无需指定索引
mIndexArray=()
mIndexArray+=(‘foo’)
mIndexArray+=(‘bar’)

取值 – 如何取值及打印整个数组?
从数组中取值
对索引数组和关联数组进行取值方面,两者直接并无太大差异:

echo ${mIndexArray[5]}
echo ${mAssociativeArray[five]}
echo ${mArray[$var]}
ehco ${mArray[var with space]}

打印整个数组[……]

READ MORE

「Shell」- 从数组中,随机选择元素

问题描述
在多数高级语言中,从数组或列表中随机获取元素是很常见的事情。那么在 Shell 中,也不例外,我们也会遇到需要从数组中随机获取元素的需求。
该笔记将记录:在 Shell 中,如何从数组中随机获取元素。
注意事项
并不是每种 Shell 都支持数组,例如 Bash 支持数组,但是 Bourne Shell (sh) 并不支持数组。我们希望可以写出可移植性高的代码,因此我们不会针对特定 Shell 来编写代码。该笔记也将记录更加通用的方法(但是,代码可能会比较难看)。
如果我们的需求复杂、数组复杂,我们会使用 Python Perl 脚本来处理,而不会使用 Shell 处理。
适用于 Bourne shell 的脚本
# 08/04/2020

#!/bin/sh

list=”aes aes-128 aes-192 salsa20 blowfish twofish cast5 3des tea xtea xor sm4″
set — $list
shift $(expr $RANDOM % $#)
KCPTUN_CRYPT=”$1″

echo $KCPTUN_CRYPT

set:将 $list 的值作为当前 Shell 参数,就好像在执行脚本时传入这些参数; shift:“洗牌”。由于参数是不确定的,所以没人知道第一个参数将是谁,也就是我们要获取的参数;
# 02/15/2021

#!/bin/sh

a=”\
111111111111111111111111111111F\n
2222222222222222222222222222222\n
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n
ccccccccccccccccccccccccccccccc\n
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF”

count=$(echo -e $a | wc -l) # 行数
random_line_number=$(expr “${RANDOM}” % “${count}” + 1) # 目标行号
random_line=$(echo -e $a | awk ‘NR==’${random_line_number}’ {print;exit}’) # 读取该行

echo $random_line

参考文献
linux – Arrays in Shell Script, not Bash – Stack Overflow[……]

READ MORE

「SHELL-SCRIPTING」- 运行命令

在当前的SHELL中执行命令
Bash – executing commands in current shell Run script in current shell without . before command[……]

READ MORE

「Shell」- 文件及路径

获取当前脚本路径

SCRIPT_PATH=$(readlink -f “$0”) # 获取脚本的绝对路径
SCRIPT_FOLDER=$(dirname “$SCRIPT_PATH”) # 从绝对路径中获取脚本所在目录
echo $SCRIPT_FOLDER

该方法适用于软链接情况:即使执行的时只向脚本的软链接,此方法依旧可以获取脚本的绝对路径,而不是软链接的路径;
删除指定目录以外的目录
Remove all files except some from a directory

shopt -s extglob
rm !(textfile.txt|backup.tar.gz|script.php|database.sql|info.txt)

文件或目录查找
获取某个目录下的 Git 仓库

# 这招是从 OpenJDK 的源码中学的:「make/scripts/hgforest.sh」
ls -d ./.git ./*/.git ./*/*/.git ./*/*/*/.git ./*/*/*/*/.git 2>/dev/null

参考文献
Unix shell script find out which directory the script file resides? – Stack Overflow[……]

READ MORE

「Shell」- 在使用 Sudo 命令时,向文件中插入内容

问题描述
当使用 sudo 命令时,如果向文件中重定向内容,将产生 Permission denied 错误:

$ sudo -u root cat >> /root/.ssh/authorized_keys2 <<EOF
ssh-rsa xxxxxxxxxxxx
EOF
-bash: /root/.ssh/authorized_keys2: Permission denied

问题原因
重定向(>>)是由当前 Shell 执行的,它需要先打开文件。但是,当前 Shell 没有权限打开 authorized_keys2 文件,因此产生错误。
解释说明:重定向(>>)不是 Shell 命令,而是 Shell “符号”。当 Shell 收到命令后,需要先进行处理。如上命令,当前 Shell 需要先打开 authorized_keys2 文件,然后在 cat 输出后,将输出写入文件。(如果难以理解,可以反过来想:如果 Shell 不处理 >> 符号,那么该符号就要传递到命令中,由特定命令来处理,也就是说每个命令都要处理 >> 符号,才能实现重定向功能。很显然,这有可能,但不合理)
解决方案

echo ‘ssh-rsa xxxxxxxxxxxx’ | sudo tee -a /root/.ssh/authorized_keys2

在命令中,通过管道将内容写入文件。管道符号(|)也是由 Shell 处理的,但是管道与重定向是两种完全不同的方法。在 C 中,需要从 stdin 中读取管道数据。
参考文献
permissions – How to insert text into a root-owned file using sudo? – Unix & Linux Stack Exchange stdin – How to read piped content in C? – Stack Overflow[……]

READ MORE

「Shell」- 常用字符串操作(String)

字符串 => 字符数组
Bash: Split string into character array

echo “abcdefg” | fold -w1

echo “abcdefg” | grep -E -o .

大小写转换
How to convert a string to lower case in Bash?
字符串重复(repeat)
How can I repeat a character How do I find the width & height of a terminal window?
要在终端里打印一条分隔线,这条分隔线由”#“组成,宽度与终端的宽度相同;

# 问题一、如何重复字符串?
printf ‘#%.0s’ {1..100}

# 问题二、如何获取终端的宽度?
tput cols

# 合并后的代码
# 可能你需要在结尾加上一个换行符,默认 printf 是不带换行符的
printf ‘#%.0s’ $(seq $(tput cols))

urldecode
bash – How to decode URL-encoded string in shell? – Stack Overflow
在 Bash 中,进行 urldecode 的方法,以及相关问题处理。
这段代码从 Stack Overflow 复制而来

function urldecode() { : “${*//+/ }”; echo -e “${_//%/\\x}”; }

function urldecode() { local i=”${*//+/ }”; echo -e “${i//%/\\x}”; }

第一个写法太奇怪了,里面包含各种 Bash 知识: 1): 是为了防止 “${*//+/ }” 被当作命令来执行 2)$_ 表示前个命令的最后一个参数,也就是 “${*//+/ }” 的解析结果 3)$* 表示传入命令的全部参数 4)${p/+/ } 表示将变量 p 的 + 替换为空格,而 ${p//+/ } 表示将变量 p 的全部 + 替换为空格;[……]

READ MORE

「Shell」- 判断字符串结尾

下面围绕“判断字符串是否以.txt 结尾”展开。转变一下也同样适用于“判断字符串是否以.txt 开头”;
通用方法
方法一、使用 grep 命令

str=”/path/to/foo.txt”

# 使用 if 语句
if echo “$str” | grep -q -E ‘\.txt$’
then
echo “true”
else
echo “false”
fi

# 写成一行
echo “$str” | grep -q -E ‘\.txt$’ && echo true || echo false
grep -q -E ‘\.txt$’ <<< “$str” && echo true || echo false

方法二、使用 expr 命令

str=”/path/to/foo.txt”

# 使用 if 语句
if expr “$str” : ‘.*\.txt$’ &>/dev/null
then
echo “true”
else
echo “false”
fi

# 写成一行
expr “$str” : ‘.*\.txt$’ &>/dev/null && echo true || echo false

方法三、使用 case 指令

str=”/path/to/foo.txt”

case “$str” in
*.txt ) echo “true”;;
* ) echo “false”;;
esac

其他方法
还可以使用 AWK、SED 命令,这里就不再介绍了,方法和上面是类似的;
特定方法
BASH

# BASH 中的正则表达式
[[ “/path/to/foo.txt” =~ .*txt$ ]] && echo “true” || echo “false”

# BASH 的特殊语法
[[ “/path/to/foo.txt” = *txt ]] && echo “true” || echo “false”

参考文献
How do I do if(string.endsWith(“/”)) in shell Bash String Comparison: Find Out IF a Variable Contains a Substring[……]

READ MORE

「Shell」- 常见错误汇总

内容简介
本部分整理了Shell中的常见错误,包括脚本错误,命令错误等等。
-bash: /dev/null: Permission denied
-bash: /dev/null: Permission denied – Unix & Linux Stack Exchange
问题描述:在 Linux 中,当登录系统时,提示 /dev/null: Permission denied 消息
问题原因:多半是有人把 /dev/null 改变为常规文件;
解决方法:1)重启操作系统,2)或者,重新创建 /dev/null 文件:

rm -f /dev/null; mknod -m 666 /dev/null c 1 3[……]

READ MORE

「XML」- 可扩展标记语言(Extensible Markup Language)

XML(Extensible Markup Language,可扩展标记语言),被设计用来传输和存储数据。
XML 文档形成了一种树结构,从根开始展开。

<?xml version=”1.0″ encoding=”UTF-8″?>
<note>
<to>Learners</to>
<from>Huawei</from>
<heading>Reminder</heading>
<body>Don’t forget Reading!</body>
</note>

文件头
<?xml version=”1.0″ encoding=”UTF-8″?> 其中: 1)<?:表示一条指令的开始。 2)xml:表示此文件是XML文件。 3)version:XML版本号。”1.0″表示使用XML1.0标准版本。 4)encoding:字符集编码格式,当前仅支持UTF-8编码。 5)?>:表示一条指令的结束。
标签
标签 <note>、<to>、<from>、<heading>、<body> 为私有。XML语言没有预定义的标签,允许使用者自定义标签和文档结构。 标签格式嵌套内容。“/”表示结束当前标签。
参考文献
Wikipedia/XML[……]

READ MORE

「DTD」- Document Type Definition

DTD是什么?
文档类型定义(DTD)是“标记声明”的一个集合,用于定义SGML系列标记语言(SGML,XML,HTML)的“文档类型”。
DTD定义XML文档的结构、合法元素、属性。
简单的说:一个DTD文件描述了一个XML文件的结构。
为什么使用DTD?
通过 DTD,您的每一个XML文件均可携带一个有关其自身格式的描述。(规定XML结构)
通过 DTD,不同的组织可以一致地使用某个标准的DTD来交换数据。(规范数据结构)
而您的应用程序也可使用某个标准的DTD来验证从外部接收到的数据。(数据结构合法性检查)
如何使用DTD?
DTD用于定义XML的结构,它可以在XML文档中声明(“内联声明”),也可以引入XML文档(“外部引用声明”)。
内联声明

<?xml version=”1.0″?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don’t forget the meeting!</body>
</note>

外部引用声明
外部引用声明是将DTD与XML分离,因此需要定义两个文件:
用于定义的note.dtd文件:

<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>

包含数据的note.xml文件:

<?xml version=”1.0″?>
<!DOCTYPE note SYSTEM “note.dtd”>
<note>
<to>George</to>
<fr[……]

READ MORE

「XSL」- Extensible Stylesheet Language

XSL
可描述如何来显示 XML 文档!
XSLT
一种用于转换 XML 文档的语言;
XPath
一种用于在 XML 文档中导航的语言;
XSL-FO
一种用于格式化 XML 文档的语言;
示例内容
#1 cdcatalog.xml

<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<!– Edited with XML Spy v2007 (http://www.altova.com) –>
<?xml-stylesheet type=”text/xsl” href=”cdcatalog.xsl”?>
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
<cd>
<title>When a man loves a woman</title>
<artist>Percy Sledge</artist>
<country>USA</country>
<company>Atlantic</company>
<price>8.70</price>
<year>1987</year>
</cd>
<cd>
<title>Unchain my heart</title>
<artist>Joe Cocker</artist>
<country>USA</country>
<company>EMI</company>
<price>8.20</price>
<year>1987</year>
</cd>
</catalog>

#2 cdcatalog.xsl

<?xml version=”1.0″ encoding=[……]

READ MORE

「Nginx」- 当 autoindex on; 时,修改输出页面的格式

XSLT是什么?

使用示例
在 Nginx 的 autoindex_format xml 中,产生类似如下的输入:

<?xml version=”1.0″?>
<list>
<directory mtime=”2018-02-08T01:31:45Z”>keyboard</directory>
<directory mtime=”2018-02-08T01:31:54Z”>make</directory>
<directory mtime=”2018-02-13T06:30:57Z”>mysql</directory>
<directory mtime=”2018-08-07T07:55:17Z”>shell</directory>
<directory mtime=”2018-02-08T01:40:09Z”>vbscript</directory>
<directory mtime=”2017-04-05T09:50:39Z”>website</directory>
<file mtime=”2017-04-06T01:52:35Z” size=”1280498″>Bv9ARM.pdf</file>
<file mtime=”2016-10-19T03:34:22Z” size=”489747″>IHI0044F_aaelf.pdf</file>
<file mtime=”2016-10-19T03:34:41Z” size=”102925150″>LinuxCMDAndShellScripts.pdf</file>
</list>

相关教程
w3schools.com/XSLT Introduction W3school/XSLT 教程
参考文献
Wikipedia/XSLT[……]

READ MORE

「XML」- 杂记

操纵工具
XMLStarlet
可以用xmlstarlet命令从命令行中修改XML文件。也是在修改libvirt的域定义文件时遇到的需求,那时候我有一堆的XML文件要修改……
对于如下XML内容:

<root>
<node user=”user1″>
<tag k=”name” v=”name1″/>
</node>
<node user=”user2″>
<tag k=”network” v=”nw1″/>
</node>
<node user=”user3″>
<tag k=”foo” v=”bar”/>
</node>
</root>

如果向删除第一个<node>节点:

<node user=”user1″>
<tag k=”name” v=”name1″/>
</node>

可以执行xmlstarlet ed -d ‘//root/node[tag[@v=”name1″]]’ /path/to/file.xml命令,修改后的内容会写入标准输出。如果想写入文件,可以使用-L, –inplace选项,即xmlstarlet ed -L -d ‘//root/node[tag[@v=”name1″]]’ /path/to/file.xml命令。
参考文献 Remove XML Nodes using Unix Command Line Start working with XMLStarlet
xsltproc
这个也可以,不过好像挺复杂的,没深入研究。
参考文献
Edit xml file using shell script / command[……]

READ MORE