タイムスタンプを変更せずにファイルの最後のシングルバイトを反転してハッシュプログラムをテストしたいと思います。タイムスタンプを変更せずに維持するのは簡単ですが、UNIXユーティリティを使用してファイルの最後のバイトをどのように元に戻すことができますか?
例:最後のバイトを0xFFにXORします(これは簡単に元に戻すことができます)。
答え1
sedではありませんが、Perlでは動作するようです。
perl -pe 's/.\z/ $& ^ "\xff" /es if eof' < in > out
1行ずつ読みますが8ビットなので問題になりません。eof
最後の行はtrueで、\z
文字列の最初の端で一致します(オプションの$
最終改行の前にも一致するため、厳密に最後のバイトではありません)。置換は単に一致する文字列を XOR します。
答え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ツールは考えられません。もちろん、この場合はより安全な方法で行うことができますが(スクリプトをより複雑にする)、この必要性は標準ツールを意図した作業以上に拡張していることを示唆することができます。