Эффективное и надежное обнаружение и удаление поврежденных пустых файлов - PullRequest
0 голосов
/ 28 января 2020

Portable Shell Function / Script для проверки файлов, которые заполнены нулевыми байтами

Я думал о просмотре подписей файлов, magi c байтов и т. Д. c, но я не хочу использовать любые косвенные предположения (кроме, скажем, известного механизма, такого как вывод hexdump ниже)

Это то, что я использую сейчас:

#!/bin/bash 

file="$1" 
bail () { 
    >&2 echo "$file doesn't exist" 
    exit 1 
} 

[ -f "$1" ] ; [[ "$?" != 0 ]] && bail                     # Check valid filename
result="$(head -c4 "$file" | hexdump -ve '1/1 "%.2X"')"   
if [ "$result" == "0000" ] || [ "$result" == "00000000" ] # Get first 4 bytes as pre-condition
    then                                                                                                    # Check for large contiguous blocks of null 
        head -c10000 "$file" | hexdump | \
        if [[ "$(wc -l <<<"$(cat -)")" -le 4 ]]           # By virtue of pre-condition, all output must be null
        then 
            exit 2                                        # Exit Codes
         else 
            exit 0                                         # 0: File is good
        fi                                                 # 1: Validation error
    else                                                   # 2: File is cactus
        exit 0
fi                            

Идея состоит в том, что:

  • Проверка первых 4 байтов в качестве предварительного условия
  • Использование hexdump без -v для группировки нескольких наборов предварительного условия (нулевые байты)
  • Использование head -c1K для внутреннего ограничения избыточного выхода
  • Используйте wc -l check для <= 4 строк. Любое другое указывало бы на изменение с нуля. </li>

И причина некоторого дурацкого и косвенного синтаксиса в том, что bash на некоторых машинах дает мне это bash: warning: command substitution: ignored null byte in input, и я нашел чтобы обойти это.

Итерация файла через вышеописанное кажется медленной, но в настоящее время полезной:

real    0m0.026s
user    0m0.009s
sys     0m0.021s

Есть ли лучший и более эффективный способ сделать это?

1 Ответ

1 голос
/ 28 января 2020

Если все системы, где вам нужно выполнить проверку, поддерживают / dev / zero , то вы можете проверить, содержит ли файл только нулевые байты с:

[[ $(LC_ALL=C cmp -- "$file" /dev/zero 2>&1) == 'cmp: EOF on '* ]]
  • Страница справочника POSIX для cmp ( cmp (Выпуск 7 Открытых групповых спецификаций группы) ) дает точную спецификацию для вывода STDERR в локали POSIX. LC_ALL=C заставляет cmp использовать POSIX Locale , поэтому сравнение с 'cmp: EOF on '* будет работать правильно.
  • Проверка верна для пустых файлов. Если вы не хотите этого, вы можете добавить проверку на непустую проверку: [[ -s $file && ... ]].
  • -- в аргументах команды cmp защищает файлы с именами, начинающимися с - рассматривается как cmp опции.
  • Остерегайтесь очень больших файлов или файлов, которые кажутся очень большими ( разреженные файлы ). cmp может занять очень много времени для запуска таких файлов. Возможно, вы захотите пропустить файлы, размер которых превышает пороговое значение.
...