Инвертировать последний байт файла?

Думаю, должно работать что-то вроде apt list linux-\*-4.4.0-{40..80}-\*|awk -F '/' '{print $1}' |xargs apt remove.

0
01.07.2019, 22:50
3 ответа

Я сделал это сам на питоне:

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))
0
28.01.2020, 02:22

Такие инструменты, как 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 для получения размера файла. Конечно, в этом случае это можно было бы сделать более безопасным способом (, еще больше усложнив скрипт ), но эта необходимость может быть еще одним намеком на то, что мы немного расширяем стандартные инструменты за пределы их предполагаемых задач.

1
28.01.2020, 02:22

Не sed, но похоже, что это работает в Perl:

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

Он читается по строкам, но это не имеет значения, так как это 8 -битов. eofистинно в последней строке, а \zсоответствует необработанному концу строки.($также будет соответствовать перед необязательным конечным переводом строки, поэтому не строго последний байт ). Замена — это просто операция xor над совпавшей строкой.

2
28.01.2020, 02:22

Теги

Похожие вопросы