BNU-FZH

fengzhenhua@outlook.com

bash 支持一维数组(不支持多维数组),并且没有限定数组的大小。类似 C 语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0.

获取数组长度的标准方法

数组的个数称为数组长度,获取数组长度的标准方法为:

1
2
3
length=${#array_name[@]}   # 取得数组元素的个数
length=${#array_name[*]} # 同上
lengthn=${#array_name[n]} # 取得数组第n-1个元素的长度(字符串长度)

参考文章

在 Shell 脚本中经常需要添加前缀和后缀,如果使用循环的方式自然可以,但是从效率和规范上讲都不是最佳方式。本文记录标准添加前缀和后缀的方法。2024年12月14日星期六晴北京市

示例脚本

1
2
3
4
PREFIX="rajiv"
services=($( echo $* | tr -d '/' ))
echo "${services[@]/#/$PREFIX-}"
echo "${services[@]/%/-$PREFIX}"

命令解释

  • 第1行,定义前缀变量PREFIX.
  • 第2行,获取输入的所有变量,并使用tr -d去除字符/.
  • 第3行,在数组services的所有追加前缀$PREFIX-.
  • 第4行,在数组services的所有追加前缀-$PREFIX.
  • 第3,4行中的services[@]表示数组的所有元素,也可以用services[*]表示.

参考文章

在数学物理学中,格拉斯曼数(又称反交换数)是一种用于狄拉克场路径积分表示的数学架构。格拉斯曼数是以德国学者赫尔曼·格拉斯曼命名的。取任意两个格拉斯曼代数\(\theta\)\(\eta\), 则它们之间成反交换关系,即 \[\begin{equation} \theta\eta=-\eta\theta \label{eq:grassmann0} \end{equation}\] 同时格拉斯曼变量与一般的数\(x\)则为交换关系,即 \[\begin{equation} \theta x=x\theta \label{eq:grassmann1} \end{equation}\]

由于\(\theta^2=-\theta^2\), 所以有\(\theta^2=0\), 于是任意函数\(f(\theta)\)泰勒展开为 \[\begin{equation} f(\theta)=A+B\theta \label{eq:grassmann2} \end{equation}\] 既然函数\(f(\theta)\)是任意的,所以对于一个周期函数也必然成立,即 \[\begin{equation} \int f(\theta)d{\theta}=\int f(\theta+T)d{\theta} \label{eq:grassmann3} \end{equation}\] 把式\(\eqref{eq:grassmann2}\)代入到式\(\eqref{eq:grassmann3}\)可得 \[\begin{equation} \int A+B\theta d{\theta}=\int A+B\theta d{\theta}+BT\int 1 d{\theta} \label{eq:grassmann4} \end{equation}\] 由于对于任意的周期函数都成立,所以必然有 \[\begin{equation} \int 1d{\theta}=0 \label{eq:grassmann5} \end{equation}\] 对式\(\eqref{eq:grassmann2}\)积分得 \[\begin{equation} \int f(\theta)d{\theta}=B\int \theta d{\theta} \label{eq:grassmann6} \end{equation}\]\(\eqref{eq:grassmann6}\)中的积分不能对所有函数都是零,所认定义对\(\theta\)的积分为\(1\), 即 \[\begin{equation} \int \theta d{\theta}=1 \label{eq:grassmann7} \end{equation}\]

名词解释

\(SU_n(q)\)群,是指“The special unitary group”, 翻译成中文就是“特殊幺正群”。 同理\(SO_n(q)\)群,是指"The special orthogonal group", 翻译成中文就是“特殊正交群”。酉矩阵(unitary matrix)也叫幺正矩阵, 对它取复共轭再转置则等于逆矩阵,也即是幺正矩阵的转置共轭等于它的逆。当矩阵元为实数时也叫正交矩阵(orthogonal matrix),它的共轭就是它自己,所以转置即得到逆矩阵,这也就表现为矩阵的行向量间为正交关系,列向量间也为正交关系。

英文介绍

The special unitary group \(SU_n(q)\) is the set of \(n×n\) unitary matrices with determinant \(+1\) (having \(n^2-1\) independent parameters). SU(2) is homeomorphic with the orthogonal group \(O_3^+(2)\). It is also called the unitary unimodular group and is a Lie group.

Special unitary groups can be represented by matrices

\[\begin{equation}\label{eq:sug0} \begin{bmatrix} a & b \\ -\overline{b} & \overline{a} \end{bmatrix} \end{equation}\]

where \(\overline{a}a+\overline{b}b=1\) and \(a,b\) are the Cayley-Klein parameters. The special unitary group may also be represented by matrices

\[\begin{equation}\label{eq:sug1} U(\xi,\eta,\zeta)= \begin{bmatrix} e^{i\xi}\cos\eta & e^{i\zeta}\sin\eta \\ -e^{-i\zeta}\sin\eta & e^{0i\xi}\cos\eta \end{bmatrix} \end{equation}\]

or the matrices

\[\begin{equation}\label{eq:sug2} U_x(\frac{1}{2}\phi)= \begin{bmatrix} \cos(\frac{1}{2}\phi) & i\sin(\frac{1}{2}\phi) \\ i\sin(\frac{1}{2}\phi) & \cos(\frac{1}{2}\phi) \end{bmatrix} \end{equation}\]

\[\begin{equation}\label{eq:sug3} U_y(\frac{1}{2}\phi)= \begin{bmatrix} \cos(\frac{1}{2}\beta) & \sin(\frac{1}{2}\beta) \\ -\sin(\frac{1}{2}\beta) & \cos(\frac{1}{2}\beta) \end{bmatrix} \end{equation}\]

\[\begin{equation}\label{eq:sug4} U_z(\xi)= \begin{bmatrix} e^{i\xi} & 0 \\ 0 & e^{-i\xi} \end{bmatrix} \end{equation}\]

参考引文

一、 修改数组的形状

1、重塑数组形状

方法 作用
reshape() 不修改原数组的形状,返回一个视图,会影响原数组的数据
resize() 直接作用于原数组
shape() 直接作用于原数组

若不理解视图,可以通过 视图与拷贝 这篇博客进行了解。

  • ndarry.reshape()
1
2
3
4
5
6
ndarry.reshape(shape)
shape:填入生成的数组形状(元组)

特点:
1、有返回值,返回一个视图
2、不直接作用于原数组(不改变原数组的形状),但影响原数组的元素

代码:

1
2
3
4
5
6
7
import numpy as np
n1 = np.array([[2,4,3,2],[8,4,2,9],[8,3,4,9]])
# 形状
n1.shape
# (3, 4)
# reshape
n1.reshape((4,3))
  • ndarry.resize()
1
2
3
4
5
6
7
resize(shape) :谨慎使用!

shape:填入生成的数组形状(元组)

特点:
1、无返回值
2、直接作用于原数组(改变原数组的形状)

代码

1
2
3
4
5
6
n1 = np.array([[2,4,3,2],[8,4,2,9],[8,3,4,9]])
n1.resize(2,2,3)

# n1形状已修改
n1.shape
# (2, 2, 3)
  • ndarry.shape
1
2
shape
通过属性直接赋值修改(改变原数组的形状)

代码

1
2
3
4
5
6
n1 = np.array([[2,4,3,2],[8,4,2,9],[8,3,4,9]])
# 数组的原始形状
n1.shape
# (4, 3)
n1.shape = (2,6)
n1

2、多维数换向一维数组转换

  • ndarry.ravel()
1
2
3
4
5
6
7
ndarry.ravel(order=)

当不设置参数order,默认将数组横向展平为一维数组
当设置参数order = 'F',即为将数组纵向展平为一维数组

注意:
使用ravel函数修改形状,得到一个视图,不会改变原数组的形状,但会会改变原数组中的元素!

代码

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
n1
# array([[2, 4, 3],
# [2, 8, 4],
# [2, 9, 8],
# [3, 4, 9]])
# 横向展平为一维数组
n1.ravel()
# array([2, 4, 3, 2, 8, 4, 2, 9, 8, 3, 4, 9])
# 纵向展平为一维数组
n1.ravel(order='F')
# array([2, 2, 2, 3, 4, 8, 9, 4, 3, 4, 8, 9])
# 原数组形状未改变
n1
# array([[2, 4, 3],
# [2, 8, 4],
# [2, 9, 8],
# [3, 4, 9]])
# 修改元素
n1.ravel()[3] = 77
# 原数组数据被修改
n1
# array([[ 2, 4, 3],
# [77, 8, 4],
# [ 2, 9, 8],
# [ 3, 4, 9]])
  • ndarry.flatten()
1
2
3
4
5
6
7
8
ndarry.flatten(order=)

当不设置参数order,默认为将数组横向展平为一维数组
当设置参数order = 'F',则将数组纵向展平为一维数组

注意:
使用flatten函数不会对原数组产生任何影响
(原数组形状和元素都不受其影响)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
n1
# array([[ 2, 4, 3],
# [77, 8, 4],
# [ 2, 9, 8],
# [ 3, 4, 9]])
# # 将数组横向展平成一维数组
n1.flatten()
# array([ 2, 4, 3, 77, 8, 4, 2, 9, 8, 3, 4, 9])
# 展平时候的形状
n1.flatten().shape
# (12,)
# 将数组纵向展平成一维数组
n1.flatten(order='F')
# array([ 2, 77, 2, 3, 4, 8, 9, 4, 3, 4, 8, 9])
# flatten修改元素数值
n1.flatten()[1] = 6
# 不影响原数组的形状和元素数据
n1
# array([[ 2, 4, 3],
# [77, 8, 4],
# [ 2, 9, 8],
# [ 3, 4, 9]])
  • ndarry.reshape(-1)

函数说明

1
2
3
4
5
6
7
8
9
10
11
12
n1.reshape(-1)
-1:表示自动计算

n1.reshape(m,-1)
指定行为m,列自动计算

n1.reshape(-1,n)
指定列为n,行自动计算

注意:
1、不影响原数组的形状
2、影响原数组的元素

代码

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
n1
# array([[ 2, 4, 3],
# [77, 8, 4],
# [ 2, 9, 8],
# [ 3, 4, 9]])
# 横向展平
n1.reshape(-1)
# array([ 2, 4, 3, 77, 8, 4, 2, 9, 8, 3, 4, 9])
# 同n1.reshape(-1) 数组只有一个维度,自动计算长度
n1.reshape(-1,)
# array([ 2, 4, 3, 77, 8, 4, 2, 9, 8, 3, 4, 9])
# 指定列数,自动计算行数
n1.reshape(-1,6)
# array([[ 2, 4, 3, 77, 8, 4],
# [ 2, 9, 8, 3, 4, 9]])
# 指定行数
n1.reshape(3,-1)
# array([[ 2, 4, 3, 77],
# [ 8, 4, 2, 9],
# [ 8, 3, 4, 9]])
# 不改变原数组的形状
n1
# array([[ 2, 4, 3],
# [77, 8, 4],
# [ 2, 9, 8],
# [ 3, 4, 9]])
# 通过reshape修改元素,原数组元素数据产生变化
n1.reshape(-1,)[0] = 12
n1
# array([[12, 4, 3],
# [77, 8, 4],
# [ 2, 9, 8],
# [ 3, 4, 9]])

3、 增加一个维度

  • np.newaxis() 所在位置增加一个维度

一维扩展为二维

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
# 一维度数组
n2 = np.arange(10)
n2
# array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
n2.shape
# (10,)
# 行方向增加一个维度
n2[np.newaxis,:]
# array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
n2[np.newaxis,:].shape
# (1, 10)
# 列方向增加一个维度
n2[:,np.newaxis]
# array([[0],
# [1],
# [2],
# [3],
# [4],
# [5],
# [6],
# [7],
# [8],
# [9]])

n2[:,].shape
# (10, 1)

二维扩展为三维

1
2
3
4
5
6
7
8
9
# 二维度数组
n2 = np.arange(10).reshape(2,5)
n2.shape
# (2, 5)
n2[np.newaxis,:,:]
# array([[[0, 1, 2, 3, 4],
# [5, 6, 7, 8, 9]]])
n2[np.newaxis,:,:].shape
# (1, 2, 5)

以此类推,将小维度数组扩展成更多维的数组。

4、数组行列转置

  • ndarray.T 属性
1
2
3
4
5
6
7
8
9
10
n2
# array([[0, 1, 2, 3, 4],
# [5, 6, 7, 8, 9]])
# ndarray.T 将数据按照对角线进行行列倒置,行变成了列,列变成了行
n2.T
# array([[0, 5],
# [1, 6],
# [2, 7],
# [3, 8],
# [4, 9]])
  • ndarray.transpose()
1
2
3
4
5
6
7
# 同ndarray.T 
n2.transpose()
# array([[0, 5],
# [1, 6],
# [2, 7],
# [3, 8],
# [4, 9]])
  • ndarray.swapaxes(1,0)
1
2
3
4
5
6
7
# 必须填入两个参数,进行行列转换
n2.swapaxes(1,0)
# array([[0, 5],
# [1, 6],
# [2, 7],
# [3, 8],
# [4, 9]])

二、数据的拼接(合并)

  • np.hstack() 水平拼接
1
2
3
4
np.hstack(tup) 数组的水平拼接
水平拼接即为横向拼接,数组的行数要一致

tup:ndarray序列

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 准备数组1
a1 = np.array([[3,4,5],[2,4,1],[8,9,4]])
a1
# array([[3, 4, 5],
# [2, 4, 1],
# [8, 9, 4]])
# 准备数组2
a2 = np.array([[7,3,1,5],[3,9,4,1],[2,8,7,4]])
a2
# array([[7, 3, 1, 5],
# [3, 9, 4, 1],
# [2, 8, 7, 4]])
# 进行水平拼接
np.hstack([a1,a2])
# array([[3, 4, 5, 7, 3, 1, 5],
# [2, 4, 1, 3, 9, 4, 1],
# [8, 9, 4, 2, 8, 7, 4]])
  • np.vstack() 竖直拼接
1
2
3
4
np.vstack(tup) 数组的水平拼接
竖直拼接即为纵向拼接,数组的列数要一致

tup:ndarray序列

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 准备数组1
a2 = np.array([[7,3,1,5],[3,9,4,1],[2,8,7,4]])
a2
# array([[7, 3, 1, 5],
# [3, 9, 4, 1],
# [2, 8, 7, 4]])
# 准备数组2
a3=np.arange(12).reshape(3,4)
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
# 进行竖直拼接
np.vstack((a3,a2))
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11],
# [ 7, 3, 1, 5],
# [ 3, 9, 4, 1],
# [ 2, 8, 7, 4]])
  • np.concatenate() 指定数组的拼接方向
1
2
3
4
np.concatenate((a1, a2, ...), axis=0, out=None)

axis = 0 :按照行的方向进行拼接,竖直拼接
axis = 1 :按照列的方向进行拼接,横向拼接

代码

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
# 准备数组1
a1 = np.array([[3,4,5],[2,4,1],[8,9,4]])
a1
# array([[3, 4, 5],
# [2, 4, 1],
# [8, 9, 4]])
# 准备数组2
a2 = np.array([[7,3,1,5],[3,9,4,1],[2,8,7,4]])
a2
# array([[7, 3, 1, 5],
# [3, 9, 4, 1],
# [2, 8, 7, 4]])
# 按照列的方向进行拼接,横向拼接
np.concatenate((a1,a2),axis = 1)
# array([[3, 4, 5, 7, 3, 1, 5],
# [2, 4, 1, 3, 9, 4, 1],
# [8, 9, 4, 2, 8, 7, 4]])
# 准备数组3
a3=np.arange(12).reshape(3,4)
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
# 按照行的方向进行拼接,竖直拼接
np.concatenate((a3,a2),axis = 0)
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11],
# [ 7, 3, 1, 5],
# [ 3, 9, 4, 1],
# [ 2, 8, 7, 4]])

三、 数据的复制

  • np.tile(ndarry,(m,n)) 指定数组的方向复制
1
2
3
4
np.tile(ndarry,(m,n))
tile是瓷砖的意思,顾名思义,这个函数就是把数组像瓷砖一样铺展开来。
m:表示按照行的方向进行复制,铺展m次
m:表示按照列的方向进行复制,铺展n次

代码

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
a2
# array([[7, 3, 1, 5],
# [3, 9, 4, 1],
# [2, 8, 7, 4]])

# 按照行的方向进行复制,铺展3次,竖直铺展
np.tile(a2,(3,1))
# array([[7, 3, 1, 5],
# [3, 9, 4, 1],
# [2, 8, 7, 4],
# [7, 3, 1, 5],
# [3, 9, 4, 1],
# [2, 8, 7, 4],
# [7, 3, 1, 5],
# [3, 9, 4, 1],
# [2, 8, 7, 4]])
# 按照列的方向进行复制,铺展2次,横向铺展
np.tile(a2,(1,2))
# array([[7, 3, 1, 5, 7, 3, 1, 5],
# [3, 9, 4, 1, 3, 9, 4, 1],
# [2, 8, 7, 4, 2, 8, 7, 4]])
# 分别按照行列方向进行铺展
np.tile(a2,(2,3))
# array([[7, 3, 1, 5, 7, 3, 1, 5, 7, 3, 1, 5],
# [3, 9, 4, 1, 3, 9, 4, 1, 3, 9, 4, 1],
# [2, 8, 7, 4, 2, 8, 7, 4, 2, 8, 7, 4],
# [7, 3, 1, 5, 7, 3, 1, 5, 7, 3, 1, 5],
# [3, 9, 4, 1, 3, 9, 4, 1, 3, 9, 4, 1],
# [2, 8, 7, 4, 2, 8, 7, 4, 2, 8, 7, 4]])

参考文章

CSV 文件格式是存储数据的最简单和有用的格式, 本文记录将 NumPy 数组保存为 CSV 文件的不同方法。

使用 Dataframe.to_csv() 将 NumPy 数组转换为 CSV

该方法用于将 Dataframe 写入 CSV 文件中。将数组转换为 pandas Dataframe ,然后将其保存为 CSV 格式。

1
2
3
4
5
6
7
8
9
10
11
# import necessary libraries
import pandas as pd
import numpy as np
# create a dummy array
arr = np.arange(1,11).reshape(2,5)
# display the array
print(arr)
# convert array into dataframe
DF = pd.DataFrame(arr)
# save the dataframe as a csv file
DF.to_csv("data1.csv")

使用 numpy_array.tofile() 将一个 NumPy 数组转换为 CSV

该方法用于将一个数组写入文件中。创建一个数组,然后将其保存到 CSV 文件中。

1
2
3
4
5
6
7
8
9
10
# import the necessary library
import numpy as np
# create a dummy array
arr = np.arange(1,11)
# display the array
print(arr)
# use the tofile() method
# and use ',' as a separator
# as we have to generate a csv file
arr.tofile('data2.csv', sep = ',')

使用 numpy.savetext() 将一个 NumPy 数组转换为 CSV

该方法用于保存一个数组到一个文本文件。创建一个数组,然后将其保存为 CSV 文件。

1
2
3
4
5
6
7
8
# import numpy library
import numpy
# create an array
a = numpy.array([[1, 6, 4],
[2, 4, 8],
[3, 9, 1]])
# save array into csv file
numpy.savetxt("data3.csv", a, delimiter = ",")

使用文件处理将 NumPy 数组转换为 CSV 文件

格式化器通过使用 str.format 函数和一对大括号()将一个或多个替换字段和占位符插入一个字符串中。该值将被插入占位符中,并与作为输入提供给 format函数的字符串连接。 with 是用来写进 CSV 文件的。

1
2
3
4
5
6
7
8
9
10
11
12
# import numpy library
import numpy
 
# create an array
a = numpy.array([[1, 6, 4],
[2, 4, 8],
[3, 9, 1],
[11, 23, 43]])
# save array into csv file
rows = ["{},{},{}".format(i, j, k) for i, j, k in a]
text = "\n".join(rows)
with open('data3.csv', 'w') as f: f.write(text)

参考文章

Next 是一款优秀的 Hexo 博客主题。 随时间的推移,Next 主题已经升级到了 Next 8.21.1, 但是升级主题的时候有时候会遇到错误,比如:

造成这些问题的主要原因在于,Next 主题升级必然有许多要修改的源码或增加的功能。而按官网的教程 theme-next 的建议,升级 Next 主题时应当把原来的主题配置文件 themes/next/_config.yml 复制到根目录,也就是和 themes 一个目录,并且命名为 _config.next.yml, 这样升级主题后配置文件由于没被覆盖而得以保留自定义设置。但是这造成另一个问题,假如升级前后两个版本的差异过大,导致有些功能上的删减,那原来的配置有可能就不再被新主题兼容,这样再生成博客就会导致出错。同时,由于配置文件没有被修改,新配置就不会生效,所以升级后应当将原配置文件 _config.next.ymlthemes/next/_config.yml 对比,找出不同,修改成新主题的配置方式,这样就可以正常使用新系统了。

文本中的重复行,基本上不是我们所要的,所以就要去除掉。使用uniq的时候要注意以下二点:

uniq 的语法

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
用法:uniq [选项]... [输入文件 [输出文件]]
从 <输入文件>(或标准输入)中过滤内容相同的相邻的行,
并写到 <输出文件>(或标准输出)。

不带选项时,内容相同的行将仅输出一次。


长选项的必选参数对于短选项也是必选的。
-c, --count 在每行之前加上该行的重复次数作为前缀
-d, --repeated 只输出重复的行,每组重复的行输出一次
-D 输出所有重复的行
--all-repeated[=方法] 类似 -D,但支持在每组重复的行之间添加一行空行;
方法={none(默认),prepend,separate}
-f, --skip-fields=N 不要比较前 N 个字段
--group[=方法] 分组输出所有项目,每组之间用空行分隔;
方法={separate(默认),prepend,append,both}
-i, --ignore-case 比较时忽略大小写
-s, --skip-chars=N 不要比较前 N 个字符
-u, --unique 只输出不重复(内容唯一)的行
-z, --zero-terminated 以 NUL 空字符而非换行符作为行分隔符
-w, --check-chars=N 每行最多比较 N 个字符
--help 显示此帮助信息并退出
--version 显示版本信息并退出

字段指的是空白字符(通常是空格和/或制表符)的序列,后跟非空白字符的序列。
程序将先跳过字段 (--skip-fields),后跳过字符 (--skip-chars)。

除非重复的行是相邻的,否则 "uniq" 将无法检测到它们。
您可能需要事先对输入进行排序,或使用 "sort -u" 而无需接着使用 "uniq"

GNU coreutils 在线帮助:<https://www.gnu.org/software/coreutils/>
请向 <http://translationproject.org/team/zh_CN.html> 报告任何翻译错误
完整文档 <https://www.gnu.org/software/coreutils/uniq>
或者在本地使用:info '(coreutils) uniq invocation'

uniq 处理文件重复数据

经常有这样的需求:两个文本文件要求取重复的行或只取不重复的,但是uniq只能处理相邻重复的行,所以需要借助于sort命令,先排序。利用现存两个文件 file1file2,生成一个新的文件。

取出两个文件的并集(重复的行只保留一份)

1
cat file1 file2 | sort | uniq

取出两个文件的交集(只留下同时存在于两个文件中的文件,重复行)

1
cat file1 file2 | sort | uniq -d

删除交集,留下其他的行(非重复行)

1
cat file1 file2 | sort | uniq -u

注意:对文本操作时,若域中为先空字符(通常包括空格以及制表符),然后非空字符,域中字符前的空字符将被跳过。

矢量分析在电动力学中具有无可替代的作用和地位,但是学过电动力学的人都知道 Maxwell 方程组, 而今天我却要为 Maxwell 方程组的积分形式重申一下它们的名字。

牛顿-莱布尼兹公式

\[\begin{equation}\label{eq:n-l} \int_{\partial \gamma} f=\int_\gamma (\nabla f)\cdot ds \end{equation}\]

梯度场通常对应于静电场,因为电场强度是电势的梯度,它的典型特点就是积分与路径无关,或都说存在原函数,满足牛顿-莱布尼兹公式。

斯托克斯公式

\[\begin{equation}\label{eq:stokes} \int_{\partial S}A\cdot ds=\int_{S}(\nabla \times A)\cdot d\sigma \end{equation}\]

这个公式比较厉害,用斯托克斯一个人的名字命名. 这个公式描述的是磁感应强度是矢势的旋度, 它把磁通量用矢势的线积分表示了出来。

高斯-奥斯特罗格拉德斯基公式

\[\begin{equation}\label{eq:g-a} \int_{\partial V}V\cdot dd\sigma =\int_V (\nabla\cdot B)dV \end{equation}\]

这个公式,多数人都知道是高斯公式,但是它却还有另一个人:奥斯特罗格拉德斯基,这点还是需要大家注意的。唉,看来,起名字不能太长,不然不容易被人记住。

作为一名科研人员,从一些知名期刊下载论文是一个重要的工作。然而,有些网站要么打不开,要么特别慢,然后这些科研网站又都是正规的网站。本文发布一款shell脚本来彻底解决这一痛点。

注意:本文发布有脚本目前仅支持Arch Linux,主要是安装依赖关系,其他Linux发行版可以自行修改。暂无发布Windows版的计划,如果您可以用Python实现对Windows的支持,欢迎联系本人共同拓展syndns.sh.

脚本编写思路

当前的网络设备已经完全可以满足大众上网的需求,一些网站为了增加功能等,会默认调用大量的js脚本等,因此打开这个网站时就会附加后台打开若干网站。通过后台链接传输的数据不是很大,现行的网速完全可以几乎瞬时完成,造成访问不畅通的瓶颈在于DNS,因为DNS不断的去解析这些网站包括的所有域名,在来来回回的解析过程中耽误了大量的时间,所以本脚本的核心思路在于解决DNS解析痛点。 整体方法包括:

  • 针对大众: 根据大家常用的网站,把这些网站的IP和域名统一写入本地/etc/hosts, 这样每次访问这些高频网站,系统就会从本地寻址,加快了解析速度。
  • 针对个人: 从firefox导出近几个月的历史记录~/bookmarks-2024-12-02.json, 然后执行syndns, 脚本自动从历史记录中把您自己常用的网站通过谷歌的8.8.8.8解析出可靠的IP列表,并写入到本地文件~/.host_dns_autoadd.txt, 然后syndns会把它载入到内存供dnsmasq调用。
  • 安装 dnsmasq 并启用,实现本地作为 DNS 服务器的功能,同时把 /etc/hosts~/.host_dns_autoadd.txt 中的映射关系统一放入内存 /dev/shm/dnsrecord.txt 文件中, 之后 dnsmasq 每次查询IP就会读取一次文件 /dev/shm/dnsrecord.txt , 而这成为最快的方式。如果不调入内存,那每次查询 IP , 系统都会去读取 /etc/hosts, 这个文件位于硬盘上,所以它的读取速度不是最快的,相对而言固态硬盘要比机械硬盘好很多,但是仍然远不如内存快, 所以调入内存是终极大招。

脚本源码

本文发布之时(2024年12月02日) syndns.sh 版本为 V1.5 , 最新脚本请前往:

syndns.sh
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#! /bin/sh
#
# Program : syndns.sh
# Version : v1.5
# Date : 2024-12-02 11:20
# Author : fengzhenhua
# Email : fengzhenhua@outlook.com
# CopyRight: Copyright (C) 2022-2025 FengZhenhua(冯振华)
# License : Distributed under terms of the MIT license.
#
# 检测软件依懒, 若未检测到,则自动安装
SYNDNS_DEPEND(){
for VAR in $1 ;do
pacman -Qq $VAR &> /dev/null
if [[ $? != 0 ]]; then
sudo pacman -S $VAR
fi
done
}
# 变量
SYN_EXE="/usr/local/bin/${0%.sh}"
SYN_AUTO="$HOME/.config/autostart/${0%.sh}.desktop"
SYN_SUDO="/etc/sudoers.d/01_$USER"
SYN_HOS="/etc/hosts"
SYN_REC=$(grep "addn-hosts" /etc/dnsmasq.conf |grep "/dev/shm/")
SYN_REC=${SYN_REC#*=}
SYN_ADD="$HOME/.host_dns_autoadd.txt"
#
# 主程序
SYNDNS_PROCESS(){
cat $SYN_HOS |grep -v '^$'|grep -v '^#'|sort |uniq -u > $SYN_REC
if [ -e $SYN_ADD ]; then
cat $SYN_ADD |grep '^[0-9]' |grep -v '^$'|grep -v '^#'|sort |uniq -u >> $SYN_REC
fi
echo "$(hostname -i) localhost:" >> $SYN_REC
systemctl is-active --quiet dnsmasq
if [[ $? == 0 ]]; then
sudo systemctl restart dnsmasq.service
else
sudo systemctl start dnsmasq.service
fi
}
# 安装和更新
if [ $# -gt 0 ]; then
if [ $1 == "-i" -o $1 == "-I" ]; then
SYNDNS_DEPEND "dnsutils inetutils dnsmasq jq"
sudo cp -f $0 $SYN_EXE
sudo chmod +x $SYN_EXE
if [ ! -e $SYN_AUTO ]; then
sudo touch $SYN_AUTO
cat > $SYN_AUTO <<EOF
[Desktop Entry]
Name=SynDns
TryExec=syndns
Exec=$SYN_EXE
Type=Application
Categories=GNOME;GTK;System;Utility;TerminalEmulator;
StartupNotify=true
X-Desktop-File-Install-Version=0.22
X-GNOME-Autostart-enabled=true
Hidden=false
NoDisplay=false
EOF
sudo sh -c "cat > /etc/dnsmasq.conf" <<EOA
domain-needed
bogus-priv
resolv-file=/etc/resolv.conf
no-poll
interface=lo
listen-address=127.0.0.1
bind-interfaces
no-hosts
addn-hosts=/dev/shm/dnsrecord.txt
cache-size=9999
port=53
EOA
fi
if [ ! -e $SYN_SUDO ]; then
sudo touch $SYN_SUDO
sudo sh -c "cat > $SYN_SUDO" <<EOB
$USER ALL=(ALL) NOPASSWD: /bin/systemctl start stirling-pdf.service, /bin/systemctl stop stirling-pdf.service, /bin/systemctl restart dnsmasq.service, /bin/systemctl start dnsmasq.service
EOB
fi
elif [[ $1 =~ ".json" ]]; then
Address=($(cat $1|jq -r '.children[]' |grep "\"uri\":"))
Address=(${Address[*]#*//})
Address=(${Address[*]/\"uri\":})
Address=(${Address[*]%%/*})
Address=(${Address[*]%%\"*})
Address=(${Address[*]%%*[0-9]}) # 去除非域名
Address=(`echo ${Address[@]}|sed -e 's/ /\n/g'|sort |uniq`)
if [ -e $SYN_ADD ]; then
rm $SYN_ADD
fi
touch $SYN_ADD
for i in ${Address[*]} ; do
unset SYN_IP
SYN_IP=($(dig @8.8.8.8 +short $i)) # 默认从Google Public DNS 解析历史IP
SYN_IP=(${SYN_IP[*]%%*\.})
for ipc in ${SYN_IP[*]}; do
echo "$ipc $i" >> $SYN_ADD
let j+=1
done
done
SYNDNS_PROCESS
fi
fi
# 默认执行主程序
SYNDNS_PROCESS

使用方法

  1. 将上述脚本 syndns.sh 保存到本地,并赋于执行权限
    1
    sudo chmod+x syndns.sh
  2. 安装脚本
    1
    syndns.sh -i
  3. 导入由firefox生成的历史记录文件:
    1
    syndns ~/bookmarks-2024-12-02.json

注意:Firefox 生成历史记录文件方法,历史管理历史导入和备份备份...

参考文章