为什么cat会改变二进制文件的内容?

时间:2016-01-26 03:24:46

标签: linux bash shell unix cat

显然,在二进制文件上运行cat并回显内容似乎不起作用。这是我制作的简单脚本:

#!/bin/sh

CONTENTS=$(cat "$1")
mv "$2" "$1"
echo "$CONTENTS" > "$2"

出于某种原因,当我做这样的事情时,这似乎搞得一团糟:

script first.pptx second.pptx

运行此文件后,新的first.pptx文件打开正常,但新second.pptx文件的格式可能无效。

为什么会发生这种情况,我该怎么做才能解决这个问题?

3 个答案:

答案 0 :(得分:4)

构造$(cat "$1")将取代文件中的任何尾随换行符,然后替换该值(以便CONTENTS将最终得到的结果)。

echo "$CONTENTS"将截断第一个NUL字符的内容,并附加换行符。

因此,如果文件没有以一个换行符结尾,则内容将稍微改变。如果它有任何NUL字符,它将被截断。

答案 1 :(得分:3)

此处有cat 不更改值内容的证据,以及您实际尝试实施的脚本,实际上没有实际价值可以用bash编写:

#!/bin/bash

declare -a arr=( )
{
    while IFS= read -r -d '' s; do
        arr+=( "$s" )
    done
    arr+=( "$s" )
} < <(cat "$1")  ## aside: this would be more efficiently just <"$1" without the cat

mv "$2" "$1"

{
    printf '%s\0' "${arr[@]:0:${#arr[@]}-1}"
    printf '%s' "${arr[@]:${#arr[@]}-1}"
} >"$2"

现在,这是如何工作的?

  • arr是一个shell数组;每个元素都是一个C字符串。
  • while IFS= read -r -d '' s以递增方式将输入文件中的NUL分隔字符串读入s。它只返回true,而这些字符串是NUL终止的;如果字符串不存在NUL终止符,则仍会填充变量s,但read命令返回false。 [有关while read成语的更多信息,请参阅BashFAQ #001
  • ...因此,数组的最后一个元素包含在最终NUL之后的内容
  • printf '%s\0' ...在格式字符串(在...区域中)后跟NUL分隔符后发出每个参数。跳过第一个${#arr[@]}后,arr扩展为数组${arrayname[@]:SEEK:COUNT}中的条目数,COUNT扩展为数组arrayname中的SEEK项} items;因此,${arr[@]:0:${#arr[@]}-1}扩展到数组arr中除最后一项之外的所有项目,然后打印这些项目后跟一个NUL。
  • 最后的printf在最后一个NUL之后发出尾随内容 - 来自最后一个数组条目。

如果运行此命令,您将观察到输入文件的md5sums交换,即使它们是包含NUL值的二进制文件。因此,您的问题的前提是错误的:cat 更改二进制文件的内容。

答案 2 :(得分:0)

尝试使用临时文件执行相同操作。

cat < $file1 > $tempFile
cat < $file2 > $file1
cat < $tempFile > $file2
rm $tempFile