我想使用命令比较两个文件 - “orienv”和“currenv” diff
。
我创建这两个文件的方式如下:
创建“currenv”文件
$cat /proc/1/environ >> currenv $cat /pcoc/279/environ >> currenv $cat /proc/295/environ >> currenv //295 is the pid of the current console
创建 orienv 文件
$printenv > orienv
然后我打电话diff
如下
diff -u orienv currenv
并得到以下输出
二进制文件 orienv 和 currenv 不同
我期待diff
带有标志的正常输出-u
(例如,显示其中差异的输出)帅哥,指示哪个文件具有另一个文件没有的信息。
什么地方出了错?
答案1
环境变量的值可以包含换行符。在 中,变量由空字节分隔,空字节不能出现在环境变量的值或名称中。 (这并非巧合,这就是环境在内存中的表示方式。)当 diff 看到空字节时,它确定该文件是二进制文件(根据定义这是正确的:文本文件不包含空字节)并放弃显示差异,因为对于大多数二进制格式, diff 打印出来的内容是没有用的。/proc/PID/environ
您可以告诉 diff 继续并将文件视为文本diff --text
,但如果您在两个文件之间执行此操作,则可能会显示仅包含一两个大更改行的显示,因为实际上环境并不包含许多换行符。 Diff 仅适用于以换行符分隔的行。如果您在 的内容和 的输出之间执行此操作,则表示一切都已更改,因为使用换行符作为分隔符。/proc/PID/environ
/proc/PID/environ
printenv
printenv
要获得有用的输出,请将空字节转换为换行符。这样每个环境变量都会从一行的开头开始。
diff -u orienv --label=currenv <(tr '\0' '\n' <currenv)
为了获得有用且明确的输出,还将换行符转换为空字节,以便每个环境变量都位于自己的单行上。然后,如果 diff 输出中存在空字节,则表明原始文件在该位置包含换行符。
diff -u --text --label=currenv <(tr '\0\n' '\n\0' <currenv1) --label=currenv <(tr '\0\n' '\n\0' <currenv2)
答案2
/proc/*/environ 不是文本文件。使用字符串:
strings /proc/{1,279,295}/environ >> currenv
env > orienv
diff -u orienv currenv
答案3
问题是因为/proc/<pid>/environ
包含空字节。您可以通过 来查看表示为文本的不可打印字节cat -v
,例如您可以^@
在下面的输出中看到表示空字节:
$ cat -v /proc/20148/environ
CLUTTER_IM_MODULE=xim^@COLORFGBG=15;0^@COLORTERM=truecolor^@ ...cont.
尽管如此,打印环境变量时仍需要考虑三个常见问题:
- 这ANSI 颜色转义码值将在终端上打印为“颜色”而不是文字,例如
export p_red=$(tput setaf 1)
。这会导致您的 diff 输出不需要的颜色,并且还会丢失颜色代码值。diff --color=always
由于颜色中断,也将无法按预期工作。 函数定义通常包含多行。而且变量值也可能包含多行。例如:
$ cat /etc/environment love=" 1st line 2nd line"
- 没有
sort
首先进行比较会得到令人困惑的结果。
您可以通过以下方式解决所有这些问题:
$ sudo cat /proc/1/environ | tr '\n\0' ' \n' | cat -v > currenv
$ sudo cat /proc/279/environ | tr '\n\0' ' \n' | cat -v >> currenv
$ sudo cat /proc/295/environ | tr '\n\0' ' \n' | cat -v >> currenv
$ sort -u currenv -o currenv
$ printenv -0 | tr '\n\0' ' \n' | cat -v | sort -u > orienv
$ diff --unified="$(cat currenv orienv | wc -l)" orienv currenv --color=always
输出将是这样的:
...
LOGNAME=xiaobai
love= 1st line 2nd line
..
PKG_CONFIG_PATH=:/usr/lib/pkgconfig:/usr/local/lib/pkgconfig
p_lblue=^[[38;5;50m
p_lgreen=^[[38;5;118m
p_lred=^[[38;5;196m
p_orig=^[(B^[[m
p_red=^[[31m
PROFILEHOME=
...
QT_IM_MODULE=ibus
+recovery=
+rootmnt=/root
S_COLORS=auto
说明:
tr '\n\0' ' \n'
表示 的缩写形式tr '\n' ' ' | tr '\0' '\n'
。我们先将换行符(即多行值)替换\n
为空' '
,然后将空字节替换\0
为换行符'\n'
。我们无需担心多行值或空字节的歧义,因为我们首先用空格替换多行值。printenv
可以-0
选择每个输出行以 NUL 结束,而不是换行符。的输出printenv -0
将与 的行为相同/proc/<pid>/environ
。所以我们也可以做同样的事情tr '\n\0' ' \n'
。sort -u
进行排序,并删除重复的行,以避免>> currenv
不断附加相同的变量而很难看出差异。- 我们将统一值设置为 value
cat currenv orienv | wc -l
来查看所有可能的统一值。diff
工具实际上调用strtoumax()
来转换该值,因此如果传递负值,您将得到垃圾值。 cat -v
将颜色代码转换为可打印文本。我们无需担心cat -v
需要单独的空字节和颜色代码,因为我们已经tr '\n\0' ' \n'
首先替换了所有空字节。- 最后,
diff --color=always
用色块(绿色/红色/白色)打印差异。我们无需担心颜色代码会中断差异颜色,因为cat -v
已经转换了颜色代码。