反转文件的最后一个字节?

反转文件的最后一个字节?

我想通过反转文件末尾的单个字节而不修改时间戳来测试我的哈希程序。保持时间戳不改变很容易,但如何使用 UNIX 实用程序来反转文件的最后一个字节?

例如:将最后一个字节与 0xFF 进行异或(这种操作很容易逆转)

答案1

不是 sed,但这似乎在 Perl 中有效:

perl -pe 's/.\z/ $& ^ "\xff" /es if eof'  < in > out

它按行读取,但这并不重要,因为它是 8 位干净的。eof在最后一行为 true,并且\z在字符串的原始末尾匹配($也将在可选的最终换行符之前匹配,因此严格来说不是最后一个字节)。替换只是对匹配字符串进行异或运算。

答案2

我自己用 python 做了:

python3 -c "import os, sys; name = sys.argv[1]; info = os.stat(name); f=open(sys.argv[1], 'rb+'); f.seek(-1,2); b = f.read(1)[0] ^ 0xFF; f.seek(-1,2); f.write(bytes([b])); print('Writing:', bytes([b])); os.utime(name, (info.st_atime, info.st_mtime))" filename

这不是最优雅的解决方案,但我相信你们有一些巧妙的 sed 技巧并且可以做得更好。

这是完整版本,您可以使用 ./invert.py (文件名)运行

import os, sys

name = sys.argv[1]
info = os.stat(name)

with open(name, 'rb+') as f:
    f.seek(-1,2)
    b = f.read(1)[0] ^ 0xFF
    f.seek(-1,2)
    f.write(bytes([b]))
    print('Writing:', bytes([b]))
    os.utime(name, (info.st_atime, info.st_mtime))

答案3

sed诸如和 之类的工具awk通常不适合查找文件,或在字节级别处理文件的内容。它们是面向行的,需要正则表达式或行号作为地址,并且没有(内置)方法来检索文件的元数据,例如文件的大小或时间戳。

也可以通过命令行工具实现您的预​​期结果,但据我所知,在任何情况下您都需要执行“粘合”操作。

这是我的尝试,只是为了好玩:(在一行上仅用于演示,根据您的意愿

(set -e -- $(ls -l <file>); pos=$(($5 - 1)); asciicode=$(od -j "$pos" -t u1 -A n "$9"); invcode=$(printf '%02x' $((asciicode ^ 0xff))); printf "\\x${invcode}" | dd of="$9" obs="$pos" seek=1)

替换<file>为您的文件名。

正如你所看到的,这并不是一句简单的话。我在某种程度上已经做到了 POSIX 兼容,但即使没有这一点,它也不会短很多。

另请注意,它不考虑文件的时间戳。要使用命令行工具来做到这一点,它会变成这样:(这次为了可读性和解释而细分

(
set -e -- $(ls -l <file>)  # <-- parsing 'ls' output generally is not a good move
pos=$(($5 - 1))            # file's size from `ls -l`, minus 1 to point to last byte
asciicode=$(od -j "$pos" -t u1 -A n "$9")  # 'od' can seek with '-j' option
invcode=$(printf '%02x' $((asciicode ^ 0xff)))  # 8-bit value read by 'od' xor-ed
                                                # and made a 0-padded 2-digits hex value
temp="$(mktemp)"                               # temporary helper file
trap 'rm -f "$temp"' EXIT                      # dispose of it in due time
touch -r "$9" "$temp"                          # copy original file's timestamp
printf "\\x${invcode}" | dd of="$9" obs="$pos" seek=1  # put computed 8-bit value in place
touch -r "$temp" "$9"                          # restore file's timestamp
)

touch -r 在临时文件上来回使用,因为这应该是保持纳秒精度的最便携的方法。

最好注意到执行解析ls输出的危险操作的必要性,但我想不出另一个 POSIX 工具来检索文件的大小。当然,在这种情况下,可以用更安全的方式来完成(使脚本更加复杂),但这种必要性可能再次暗示我们正在将标准工具延伸到超出其预期任务的范围。

相关内容