BNU-FZH

fengzhenhua@outlook.com

Mandelbrot 集简介

Mandelbrot 集是数学中一个非常著名的分形集合,它以法国数学家本华·曼德勃罗的名字命名。分形是一种具有自相似性质的几何形状,意味着无论放大多少倍,其部分看起来与整体相似。 Mandelbrot 集正是这种特性的典型代表,并且因其复杂而美丽的图形成为了计算机图形学、艺术以及数学研究中的重要主题。

Mandelbrot 集定义于复数平面上,由所有不使序列 $ z_{n+1} = z_n^2 + c $ 发散至无穷大的点 $ c $ 组成,其中 $ z_0 = 0 $。换句话说,对于每一个位于复数平面上的点 $ c $,从 $ z=0 $ 开始应用上述迭代公式,如果该序列保持有界,则点 $ c $ 属于 Mandelbrot 集;反之,如果序列趋向于无穷大,则该点不属于此集合。通常情况下,为了判断一个点是否属于 Mandelbrot 集,会设定一个最大迭代次数和逃逸半径(通常是2),如果在达到最大迭代次数前,序列的模超过了逃逸半径,则认为该点发散。

直接实现方式

直接保存为csv文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#! /usr/bin/env python3
# vim:fenc=utf-8
import numpy as np
# Mandelbrot Set参数
picname = "Mandelbrot"
file_name = f"{picname}.csv"
width, height = 1000, 1000 # 图像的宽度和高度
max_iter = 100 # 最大迭代次数

def mandelbrot_set(width, height, max_iter):
x = np.linspace(-2.5, 1.5, width)
y = np.linspace(-2, 2, height)
escape_time = np.zeros((height, width)) # 注意这里的维度顺序

for i in range(width):
for j in range(height):
c = complex(x[i], y[j])
z = 0
n = 0
while abs(z) <= 2 and n < max_iter:
z = z*z + c
n += 1
escape_time[j, i] = n # 根据像素位置更新逃逸时间

return x, y, escape_time

# 计算Mandelbrot集
x_coords, y_coords, escape_time = mandelbrot_set(width, height, max_iter)

# 将结果保存为适合Veusz导入的格式
with open(file_name, 'w') as file:
# 写入X坐标行
file.write(',' + ','.join(map(str, x_coords)) + '\n')
for j in range(escape_time.shape[0]):
# 写入每行的数据,先写Y坐标,然后是该行的逃逸时间值
file.write(str(y_coords[j]) + ',' + ','.join(map(str, escape_time[j])) + '\n')

print(f"Mandelbrot集已成功保存到{file_name}")

使用 Pandas 库保存数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#! /usr/bin/env python3
# vim:fenc=utf-8
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

def mandelbrot(c, max_iter):
z = 0
n = 0
while abs(z) <= 2 and n < max_iter:
z = z*z + c
n += 1
return n

def mandelbrot_set(xmin, xmax, ymin, ymax, width, height, max_iter):
r1 = np.linspace(xmin, xmax, width)
r2 = np.linspace(ymin, ymax, height)
m = np.empty((width,height))
for i in range(width):
for j in range(height):
m[i,j] = mandelbrot(r1[i] + 1j*r2[j], max_iter)
return m, r1, r2 # 返回m以及对应的x和y坐标值

# 设置参数并生成Mandelbrot集合
xmin, xmax, ymin, ymax = -2.0, 1.0, -1.5, 1.5
width, height = 800, 800
max_iter = 256

m, r1, r2 = mandelbrot_set(xmin, xmax, ymin, ymax, width, height, max_iter)

# 显示图像(可选)
# plt.imshow(m.T, extent=[xmin, xmax, ymin, ymax], cmap='hot', interpolation='bilinear')
# plt.colorbar()
# plt.title("Mandelbrot Set")
# plt.show()

# 将结果保存为CSV文件
# 创建一个列表来保存数据点
data_points = []
for i in range(width):
for j in range(height):
data_points.append([r1[i], r2[j], m[i, j]])

# 使用pandas DataFrame保存数据
df = pd.DataFrame(data_points, columns=['Re', 'Im', 'Iteration'])
df.to_csv('mandelbrot_set.csv', index=False)

print("Mandelbrot集合已成功保存至mandelbrot_set.csv")

Pandas 保存数据与直接保存数据的不同

在处理和存储数据时,使用Pandas的DataFrame来保存数据与直接保存数据(例如将数据保存为纯文本、CSV文件等)有着显著的区别。以下是这两种方法的主要不同点:

使用 Pandas DataFrame保存数据

结构化存储

  • 表格形式DataFrame提供了一个二维表格结构,支持行和列标签,并允许每列有不同的数据类型。
  • 强大的数据操作能力:内置了丰富的函数用于数据清洗、转换、筛选、聚合等高级功能。

索引和标签支持

  • 灵活访问:可以通过列名、行位置或布尔索引来选取子集,便于快速定位所需信息。
  • 多级索引:支持复杂的索引机制,使得数据管理和查询更加灵活。

缺失值处理

  • 自动管理缺失数据:通过NaN表示缺失值,并提供了多种方法来清理或填补这些缺失值。

数据可视化和分析集成

  • 与其他库的良好集成:可以方便地与NumPy、Matplotlib、Seaborn等科学计算和可视化库结合使用,增强数据分析能力。

直接保存数据

简单的数据格式

  • 通用性高:直接存储的数据通常保存为原始格式,如CSV、TXT、JSON等,适合于结构相对简单、规模较小的数据集。
  • 轻量级:这种保存方式不依赖于外部库,适合需要跨平台使用的场景。

有限的数据处理能力

  • 缺乏高级特性:直接存储的数据没有内置的数据处理功能,如果需要进行数据处理,则需编写额外的代码或使用其他工具。
  • 基础操作:虽然可以直接读写数据,但复杂的数据操作如过滤、分组、聚合等需要额外的努力来实现。

通用性和可移植性

  • 易于分享:由于直接存储的数据格式通常是通用的,因此可以在不同的编程语言和环境中读取和写入,增加了跨平台使用的便利性。

总的来说,选择哪种方式取决于具体的应用需求和数据特点。DataFrame 提供了一种更为强大和灵活的方式来存储和处理数据,特别适用于复杂的数据分析任务;而直接保存数据更适合于简单场景,或者当你需要一种轻量级、跨平台的数据交换方式时。

Julia 集简介

朱利亚集是分形几何中的一个重要概念,由法国数学家加斯东·朱利亚研究得出,通过迭代复数平面上的函数 \(f_c(z) = z^2 + c\) 来定义,其中 \(c\) 为固定的复数参数。对于每一个给定的 \(c\) 值,从任意初始点 \(z_0\) 开始进行迭代,如果序列 \({zn}\) 保持有界,则初始点属于该朱利亚集;反之,若序列趋向无穷大,则初始点不属于此集。这些集合并呈现出高度复杂和自相似的边界,其形态随不同的 \(c\) 值变化,从连通区域到复杂的尘埃状分布不等,展现了丰富的几何结构和美丽的图案,既是数学研究的对象,也是艺术创作的源泉。

通过计算机绘制 Julia 集,需要指定一个 \(c\) 值, 然后取一个复平面上的一个区域 \(A\), 对于此区域内的每一点按\(f(z)\)进行迭代, 同时设置一个最大迭代次数 \(N\) 和逃逸半径 \(R\). 对于复平面内的点如果\(|z|>R\), 则取强度为\(0\); 如果 \(|z|<R\), 则使用 \(f(z)\) 迭代, 当迭代 \(m\) 次后点 \(|z_m|>R\), 则取强度为\(m\), 如果迭代\(N\)次后仍然不满足\(|z_N|>R\), 则取强度为\(N\). 如此操作后,对于复平面区域\(A\)内的每一点都赋予一个强度值,然后输出为 csv 的2D数据,按强度上色就构成了一个 Julia 集的图形显示。

代码分析

声明脚本为 python3 , 用 utf-8 编码

1
2
#! /usr/bin/env python3
# vim:fenc=utf-8

调用 numpy 库, 同时设置初值 c, 并定义保存文件的名称 picname

1
2
3
4
5
6
import numpy as np
c = complex(-0.70176, -0.3842)
picname = "Nebula"
file_name = f"{picname}.csv"
width, height = 1000, 1000 # 图像的宽度和高度
max_iter = 100 # 最大迭代次数

绘制程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def julia_set(c, width, height, max_iter):
x = np.linspace(-2, 2, width)
y = np.linspace(-2, 2, height)
escape_time = np.zeros((height, width)) # 注意这里的维度顺序
for i in range(width):
for j in range(height):
z = complex(x[i], y[j])
n = 0
while abs(z) <= 2 and n < max_iter:
z = z*z + c
n += 1
escape_time[j, i] = n # 根据像素位置更新逃逸时间

return x, y, escape_time

上述程序中:

  • 第1行:定义程序julia_set, 并设置了四个参数c, width, heightmax_iter.
  • 第2行:定义x数组,将x定义域\(-2\)\(2\)划分成width等份.
  • 第3行:定义y数组,将y定义域\(-2\)\(2\)划分成height等份.
  • 第4行:定义 \(height\times width\) 矩阵escape_time,所有矩阵元默认取 \(0\).
  • 第5行:遍历x数组, 以取得每一个 \(x\)数组元 \(x[i]\).
  • 第6行:遍历y数组, 以取得每一个 \(y\)数组元 \(y[j]\).
  • 第7行:以\(x[i]\) 为实部, \(y[j]\)为虚部,构建复数\(z\).
  • 第8行:对于每一个点\(z\), 默认逃逸次数为\(n=0\).
  • 第9行:使用while对每一个点\(z\)判断,条件为小于逃逸半径2小于最大逃逸次数 max_iter.
  • 第10行:若满足条件,则迭代一次,同时逃逸次数 \(n\) 增加\(1\), 若仍然满足第9行的条件,则继续循环,同时不断将判断的逃逸次数\(n\)赋值给矩阵escape_time[j,i].
  • 第11行:返回最后的x,y,escape_time 数组.

使用上述函数处理具体的参数

1
2
# 计算Julia集
x_coords, y_coords, escape_time = julia_set(c, width, height, max_iter)

将结果保存为 csv 数据

1
2
3
4
5
6
with open(file_name, 'w') as file:
file.write(',' + ','.join(map(str, x_coords)) + '\n')
for j in range(escape_time.shape[0]):
# 写入每行的数据,先写Y坐标,然后是该行的逃逸时间值
file.write(str(y_coords[j]) + ',' + ','.join(map(str, escape_time[j])) + '\n')
print(f"Julia集已成功保存到{file_name}")

上述程序中:

  • 第1行:打开文件file_name, 同时赋予write权限(即选项w), 将其命名为file, 在后续程序中调用.
  • 第2行:写入x坐标行, 数组以逗号,分隔, 行尾添加换行符\n.
  • 第3行:遍历escape_time数组的第一列(也就是所有行数), 写入每一行的数组,仍然以逗号,分隔,行尾添加换行符\n.
  • 第4行:打印处理结果,同时使用f标记来使用变量{file_name}.

注意:通过这一段程序,我们可以判断出2d数据的具体形式构成. 第1行是x坐标点,第1列是y坐标点,由xy决定的点上则(x,y)所对应的强度值,这是一个二维数据表格,和数学上描点绘图的数据一致。

今天需要使用 veusz 处理一个 julia 集的二维图形,但是发现 veusz 不能正常启动了。由于 veusz 是一个使用 python 写的软件, 所以由于 archlinux 升级导致的问题可能性还是比较大的, 于是卸载 veusz 后重新安装,得到了错误提示:

paru -S veusz
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Traceback (most recent call last):
File "/usr/lib/python3.13/site-packages/pyproject_hooks/_in_process/_in_process.py", line 389, in <module>
main()
~~~~^^
File "/usr/lib/python3.13/site-packages/pyproject_hooks/_in_process/_in_process.py", line 373, in main
json_out["return_val"] = hook(**hook_input["kwargs"])
~~~~^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/site-packages/pyproject_hooks/_in_process/_in_process.py", line 143, in get_requires_for_build_wheel
return hook(config_settings)
File "/usr/lib/python3.13/site-packages/setuptools/build_meta.py", line 332, in get_requires_for_build_wheel
return self._get_build_requires(config_settings, requirements=[])
~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/site-packages/setuptools/build_meta.py", line 302, in _get_build_requires
self.run_setup()
~~~~~~~~~~~~~~^^
File "/usr/lib/python3.13/site-packages/setuptools/build_meta.py", line 516, in run_setup
super().run_setup(setup_script=setup_script)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/site-packages/setuptools/build_meta.py", line 318, in run_setup
exec(code, locals())
~~~~^^^^^^^^^^^^^^^^
File "<string>", line 38, in <module>
File "/home/feng/.cache/paru/clone/veusz/src/veusz-3.6.2/pyqt_setuptools.py", line 11, in <module>
import tomli
ModuleNotFoundError: No module named 'tomli'

显然提示缺少 python 库 tomli, 于是使用 archlinux 自带的包管理器 pacman 安装 tomli

install tomli
1
sudo pacman -S python-tomli

之后再安装 veusz, 则问题解决。

Shell 中的特殊变量

Shell 预定义了一些特殊变量,它们通常包含一个或两个连字符作为前缀:

  • $0 - 当前脚本的名字。
  • $1, $2, ... - 传递给脚本或函数的位置参数。
  • $# - 传递给脚本或函数的参数个数。
  • $* - 所有参数作为一个字符串。
  • $@ - 参数列表(与 $* 类似,但在引号中有区别)。
  • $? - 上一条命令的退出状态。
  • $$ - 当前 Shell 的进程 ID。
  • $! - 最后一个后台进程的 PID。

awk 内置变量

awk 提供了多个内置变量来访问输入数据和其他特性:

  • $n - 表示当前行的第 n 个字段(列),其中 $1 是第一列,$2 是第二列,依此类推。
  • $0 - 表示整个当前行的内容。
  • NF - 当前行的字段数(列数)。
  • NR - 到目前为止处理的总行数(全局行号)。
  • FNR - 当前文件中的行号(对于多文件输入,每个新文件计数会重新开始)。
  • FILENAME - 当前正在读取的文件名。
  • FS - 字段分隔符,默认为空白字符(空格或制表符)。可以设置为其他值以改变字段划分规则。
  • OFS - 输出字段分隔符,默认为空格。当使用逗号 , 分隔输出字段时,awk 会用这个值替换逗号。
  • ORS - 输出记录分隔符,默认为换行符 \n
  • RS - 输入记录分隔符,默认为换行符,即每行作为一个记录。
  • ARGCARGV - 类似于 Shell 的特殊变量,分别表示命令行参数的数量和数组。

这些内置变量提供了对输入数据结构、格式以及程序运行环境的强大控制能力。

冲突和解决

Shell 和 awk 同时内置了 $n 变量,在 Shell 脚本中使用变量会造成混乱。但是注意到:Shell 中使用双引号括起来的变量 "$n" 表示变量,而使用单引号'$n'不表示变量,但是 awk 在单引号'$n'中表示 awk 变量, 所以在任何情况下都使用单引号将 awk 的命令引起来就可以避免冲突。

参考文章

dig 命令简介

dig(Domain Information Groper)是 Linux 和 Unix 系统中用于查询 DNS(域名系统)的强大工具。它提供了对 DNS 查询的详细控制,并且可以用来执行各种类型的 DNS 查询,包括但不限于 A 记录、MX 记录、NS 记录、CNAME 记录、TXT 记录等。dig 是网络管理员和开发者调试 DNS 问题、验证域名配置以及获取有关互联网资源信息的重要工具。

主要特点

  • 多功能性:支持多种查询类型和选项,能够满足复杂的 DNS 查询需求。
  • 详细的输出:提供详尽的查询结果信息,默认情况下输出格式易于阅读,同时也支持简洁模式(如 +short)。
  • 灵活性:用户可以通过命令行参数自定义查询行为,例如指定 DNS 服务器、设置查询超时时间、递归查询等。
  • 批处理能力:支持从文件批量读取域名进行查询(使用 -f 参数),适合自动化脚本或大规模 DNS 数据收集。

基本用法

1
dig [选项] [域名] [记录类型] 

查询特定DNS服务器

1
dig @8.8.8.8 www.baidu.com

批量查询文件

创建一个包含域名列表的文本文件,并使用-f参数进行批量查询。

1
dig -f domains.txt
1
2
3
www.baidu.com
www.bing.com
www.sina.com

批量查询数组

创建一个包含域名列表的数组,并使用-f参数进行批量查询。

1
2
3
4
5
6
MH=(
www.baidu.com
www.bing.com
www.sina.com
)
printf "%s\n" "${MH[@]}" | dig @119.29.29.29 -f /dev/stdin +noall +answer | awk '{print $5, $1}'

通过dnsmasq 实现了本地 DNS 服务的功能,这大大加速的域名解析速度。但是最近在连接校园网时,发现每次连网配置文件/etc/resolv.conf都会被修改为校园网默认的配置,但是这样就无法设置为自动dnsmasq接管服务。

具体原因

当在eth接口启用DHCP后,本地resolv.conf文件将被修改,resolv.conf文件中的DNS地址将被改为从DHCP获取到的地址。这种从DHCP获得的DNS即是Peer DNS 启用DHCP后即便修改/etc/resolv.conf,不久又恢复成原样.

解决方法

  1. 断开网络
  2. /etc/resolv.conf修改为
    1
    2
    3
    4
    5
    # Generated by syndns
    nameserver 127.0.0.1
    nameserver 119.29.29.29
    nameserver 180.76.76.76
    nameserver 1.2.4.8
  3. 设置文件锁
    1
    sudo chattr +i /etc/resolv.conf
  4. 再次修改/etc/resolv.conf必须先解锁,命令为
    1
    sudo chattr -i /etc/resolv.conf

参考文章

一、问题

Shell下有时需要使用随机数,在此总结产生随机数的方法。计算机产生的的只是“伪随机数”,不会产生绝对的随机数(是一种理想随机数)。伪随机数在大量重现时也并不一定保持唯一,但一个好的伪随机产生算法将可以产生一个非常长的不重复的序列。

二、随机数

1、生成随机数的七种方法

(1)通过内部系统变量($RANDOM)

1
echo $RANDOM

生成0-32767之间的整数随机数,若超过5位可以加个固定10位整数,然后进行求余。

生成400000~500000的随机数
1
2
3
4
5
6
7
8
9
10
#!/bin/bash  
function rand(){
min=$1
max=$(($2-$min+1))
num=$(($RANDOM+1000000000)) #增加一个10位的数再求余
echo $(($num%$max+$min))
}
rnd=$(rand 400000 500000)
echo $rnd
exit 0

(2)使用awk的随机函数

1
awk 'BEGIN{srand();print rand()*1000000}' #可以加上if判断

(3)openssl rand产生随机数

openssl rand 用于产生指定长度个bytes的随机字符。-base64-hex对随机字符串进行base64编码或用hex格式显示。

1
2
openssl rand -base64 8 | md5sum | cut -c1-8 #八位字母和数字的组合,3a61800e
openssl rand -base64 8 | cksum | cut -c1-8 #八位数字,10784736

(4)通过时间获得随机数(date)

1
2
3
date +%s%N #生成19位数字,1287764807051101270
date +%s%N | cut -c6-13 #取八位数字,21793709
date +%s%N | md5sum | head -c 8 #八位字母和数字的组合,87022fda
生成1~50的随机数
1
2
3
4
5
6
7
8
9
10
#!/bin/bash 
function rand(){
min=$1
max=$(($2-$min+1))
num=$(date +%s%N)
echo $(($num%$max+$min))
}
rnd=$(rand 1 50)
echo $rnd
exit 0

(5)通过系统内唯一数据生成随机数(/dev/random及/dev/urandom)

/dev/random存储系统当前运行环境的实时数据,可看作系统某时的唯一值,提供优质随机数。

/dev/urandom是非阻塞随机数产生器,读取时不会产生阻塞,速度更快、安全性较差。

1
2
3
4
5
6
7
8
#32f1e953ac
cat /dev/urandom | head -n 10 | md5sum | head -c 10
#生成全字符的随机字符串,08?WU$ZU
cat /dev/urandom | strings -n 8 | head -n 1
#生成数字加字母的随机字符串,Ql2q9CXS,其中 strings -n设置字符串的字符数,head -n设置输出的行数。
cat /dev/urandom | sed -e 's/[^a-zA-Z0-9]//g' | strings -n 8 | head -n 1
#urandom的数据很多使用cat会比较慢,在此使用head读200行,cksum将读取文件内容生成唯一的表示整型数据,cut以” “分割然后得到分割的第一个字段数据
head-200/dev/urandom| cksum |cut-d" " -f1

(6)读取linux的uuid码

UUID码全称是通用唯一识别码 (Universally Unique Identifier, UUID),UUID格式是:包含32个16进制数字,以“-”连接号分为五段,形式为8-4-4-4-12的32个字符。linux的uuid码也是有内核提供的,在/proc/sys/kernel/random/uuid这个文件内。cat/proc/sys/kernel/random/uuid每次获取到的数据都会不同。

1
2
cat /proc/sys/kernel/random/uuid| cksum | cut -f1 -d" " #获取不同的随机整数,1675034933
cat /proc/sys/kernel/random/uuid| md5sum | cut -c1-8 #数字加字母的随机数,d69a7ebf
使用linux uuid 生成100~500随机数
1
2
3
4
5
6
7
8
9
10
#!/bin/bash 
function rand(){
min=$1
max=$(($2-$min+1))
num=$(cat /proc/sys/kernel/random/uuid | cksum | awk -F ' ' '{print $1}')
echo $(($num%$max+$min))
}
rnd=$(rand 100 500)
echo $rnd
exit 0

(7)从元素池中随机抽取取

1
2
3
pool=(a b c d e f g h i j k l m n o p q r s t 1 2 3 4 5 6 7 8 9 10)
num=${#pool[*]}
result=${pool[$((RANDOM%num))]}

用于生成一段特定长度的有数字和字母组成的字符串,字符串中元素来自自定义的池子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash 
length=8
i=1
seq=(0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
num_seq=${#seq[@]}

while [ "$i" -le "$length" ]
do
seqrand[$i]=${seq[$((RANDOM%num_seq))]}
let "i=i+1"
done

echo "The random string is:"
for j in ${seqrand[@]}
do
echo -n $j
done
echo

2、随机数应用

  1. 随机数在互联网中应用广泛如计算机仿真模拟、数据加密、网络游戏等,在登录某些论坛或游戏时,系统会产生一个由随机数字和字母组成的图片,用户必须正确输入,这是防止恶意攻击的很好的方法,因比较难破解图片格式的字符。其关键技术就是产生随机数,再使用ASP.NET等工具将这些字符串封装成图片格式以作为验证图片。

  2. 网络游戏中也常利用随机数完成一些功能,比如掷骰子、发扑克牌等。以下是连续掷1000次骰子,然后统计出1~6点的次数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #!/bin/bash 
    #RANDOM=$$
    PIPS=6
    MAX=1000
    throw=1

    one=0
    two=0
    three=0
    four=0
    five=0
    six=0
    count()
    {
    case "$1" in
    0) let "one=one+1";;
    1) let "two=two+1";;
    2) let "three=three+1";;
    3) let "four=four+1";;
    4) let "five=five+1";;
    5) let "six=six+1";;
    esac
    }

    while [ "$throw" -le "$MAX" ]
    do
    let "dice=RANDOM % $PIPS"
    count $dice
    let "throw=throw+1"
    done

    echo "The statistics results are as follows:"
    echo "one=$one"
    echo "two=$two"
    echo "three=$three"
    echo "four=$four"
    echo "five=$five"
    echo "six=$six"
    RANDOM产生的随机数基本在平均值左右浮动(即方差较小)。

  3. 批量创建10个系统帐号,密码随机 先看看指定用户密码的脚本:

    1
    2
    3
    4
    5
    6
    7
    #!/bin/bash 
    #批量创建10个系统帐号并设置密码,帐号和密码相同
    for name in `seq -w 10`
    do
    #非交互式的输入密码
    useradd linux$name && echo "linux$name" | passwd --stdin linux$name
    done
    10个用户用户名和密码相同都从linux-01到linux-10,再看看用户密码随机生成的脚本:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #!/bin/bash 
    #批量创建10个系统帐号并设置密码
    rm -f user.log
    for name in `seq -w 10`
    do
    #非交互式的输入随机密码
    password=`echo $RANDOM | md5sum | cut -c1-8`
    #可以使用password=`echo "date $RANDOM" | md5sum | cut -c3-11`
    #也可以使用password=`penssl rand -base64 8 | md5sum | cut -c1-8`
    useradd linux$name && echo password | passwd --stdin linux$name
    echo -e "user=linux$name \t passwd=$password" >> user.log #保存用户名密码以查阅
    done
    对比可以看出,随机生成密码的灵活性和保密性,管理员可以打开user.log文件,记录刚创建的十个用户的信息。

三、总结

  1. Shell产生伪随机数的函数$RANDOM,能方便地产生分布较平均的伪随机数,能满足大部分应用的需求。
  2. 产生随机数的方法还有很多并且可以扩展,扩展思路才能选择最近的方式。
  3. 完全引用自: shell产生随机数七种方法的实现

由于 linuxqq 是用 electron 写的,而且目前还有一些 bug, 当点击关闭按钮后程序仍然在后台运行。但是,想重新登录一下,却提示已经登录,而原来的聊天界面又找不到,所以必须完全关闭,然后再重新启动才行。 解决方法是借助pgrep打印所有相关进程,然后一同kill, 命令为

1
sudo kill $(pgrep qq)

由于工作和学习的需要,可能需要同时在一台电脑上维护多个 github 帐号,这时使用 Github-cli 同时使用多个帐号的 Token 认证后,然后就可以随时切换了。具体方法为:

登录认证帐号

1
gh auth login -p ssh --skip-ssh-key --with-token < your_token_here >

注意: 这条命令选择了 ssh的认证方式,所以需要提前配置好 ssh. 同时按 使用Github-Cli管理仓库 取得 Token.

切换帐号

1
gh auth switch -u < your_name_here >

gh auth 选项详解

gh help auth login
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Authenticate with a GitHub host.

The default hostname is `github.com`. This can be overridden using the `--hostname`
flag.

The default authentication mode is a web-based browser flow. After completion, an
authentication token will be stored securely in the system credential store.
If a credential store is not found or there is an issue using it gh will fallback
to writing the token to a plain text file. See `gh auth status` for its
stored location.

Alternatively, use `--with-token` to pass in a personal access token (classic) on standard input.
The minimum required scopes for the token are: `repo`, `read:org`, and `gist`.

Fine-grained personal access tokens are not supported.

Alternatively, gh will use the authentication token found in environment variables.
This method is most suitable for "headless" use of gh such as in automation. See
`gh help environment` for more info.

To use gh in GitHub Actions, add `GH_TOKEN: ${{ github.token }}` to `env`.

The git protocol to use for git operations on this host can be set with `--git-protocol`,
or during the interactive prompting. Although login is for a single account on a host, setting
the git protocol will take effect for all users on the host.

Specifying `ssh` for the git protocol will detect existing SSH keys to upload,
prompting to create and upload a new key if one is not found. This can be skipped with
`--skip-ssh-key` flag.

For more information on OAuth scopes, <https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps/>.


USAGE
gh auth login [flags]

FLAGS
-p, --git-protocol string The protocol to use for git operations on this host: {ssh|https}
-h, --hostname string The hostname of the GitHub instance to authenticate with
--insecure-storage Save authentication credentials in plain text instead of credential store
-s, --scopes strings Additional authentication scopes to request
--skip-ssh-key Skip generate/upload SSH key prompt
-w, --web Open a browser to authenticate
--with-token Read token from standard input

INHERITED FLAGS
--help Show help for command

EXAMPLES
# Start interactive setup
$ gh auth login

# Authenticate against github.com by reading the token from a file
$ gh auth login --with-token < mytoken.txt

# Authenticate with specific host
$ gh auth login --hostname enterprise.internal

LEARN MORE
Use `gh <command> <subcommand> --help` for more information about a command.
Read the manual at https://cli.github.com/manual
Learn about exit codes using `gh help exit-codes`

参考文章

在编写脚本时避免不了使用密码,所以为了增强安全性,需要使用加密解密技术。本文记录几种加密解密的方法。

Python 与 Bash Shell 的结合

这个命令会让你输入一个字符串,然后会再输出一串加密了的数字.

1
2
3
4
# 加密代码[照直输入]:
python -c 'print reduce(lambda a,b: a*256+ord(b), raw_input("string: "), 0)'
# 解密代码[数字后+P]:
dc -e 输出的数字P

纯 Bash Shell, 含 VIM 的xxd

用 gtalk@gmail.com 作为明文,加密分两步也可以一步。

1
2
3
4
5
6
7
8
# 加密代码:
echo "gtalk@gmail.com" |xxd -ps -u
# 得到:6774616C6B40676D61696C2E636F6D0A
echo "ibase=16; 6774616C6B40676D61696C2E636F6D0A" |bc
# 得到:137514765985002236391382606438443478282
一步加密代码:
echo "ibase=16; $(echo "gtalk@gmail.com" |xxd -ps -u)" |bc
# 得到:137514765985002236391382606438443478282

Base64 编码

1
2
3
4
5
6
# 加密代码:
echo "gtalk@gmail.com" |base64 -i
# 得到:Z3RhbGtAZ21haWwuY29tCg==
# 解密代码:
echo "Z3RhbGtAZ21haWwuY29tCg==" |base64 -d
# 得到:gtalk@gmail.com

Base64 编码,这个很好很强大,适合写加密脚本

实现使用 base64 加密、解密字符串并赋值给变量。网上绝大多数是使用 echo 管道实现 加密和解密字符串的输出。

1
2
3
4
5
pwd=$( base64 -d <<< MQo= )  # 解码
in=$( base64 <<< "123456") # 加密
# 或者
test=$(printf "%s""123456" | base64) # 加密
test=$(printf "%s" MTIzNDU2| base64 -d) # 解密

参考文章