Элегантный способ поиска файлов UTF-8 с помощью спецификации?

Для целей отладки мне нужно рекурсивно искать каталог для всех файлов, начинающихся с знака порядка байтов UTF-8 (BOM). Мое текущее решение – простой скрипт оболочки:

find -type f | while read file do if [ "`head -c 3 -- "$file"`" == $'\xef\xbb\xbf' ] then echo "found BOM in: $file" fi done 

Или, если вы предпочитаете короткие, нечитаемые однострочные:

 find -type f|while read file;do [ "`head -c3 -- "$file"`" == $'\xef\xbb\xbf' ] && echo "found BOM in: $file";done 

Он не работает с именами файлов, которые содержат разрыв строки, но такие файлы не ожидаются в любом случае.

Есть ли более короткое или более элегантное решение?

Есть ли интересные текстовые редакторы или макросы для текстовых редакторов?

Как насчет этой простой команды, которая не просто находит, но очищает неприятную спецификацию? 🙂

 find . -type f -exec sed '1s/^\xEF\xBB\xBF//' -i {} \; 

Мне нравится «найти» ðŸ™‚

Если вы хотите просто показать BOM-файлы, используйте следующую команду:

 grep -rl $'\xEF\xBB\xBF' . 

Самый лучший и простой способ сделать это в Windows:

Total Commander → перейти в корневой каталог проекта → найти файлы ( Alt + F7 ) → типы файлов *. * → Найти текст «EF BB BF» → установить флажок «Hex» → выполнить поиск

И вы получите список 🙂

 find . -type f -print0 | xargs -0r awk ' /^\xEF\xBB\xBF/ {print FILENAME} {nextfile}' 

Большинство приведенных выше решений проверяют больше, чем первая строка файла, даже если некоторые (например, решение Маркуса) фильтруют результаты. Это решение проверяет только первую строку каждого файла, поэтому оно должно быть немного быстрее.

Если вы принимаете ложные срабатывания (в случае отсутствия текстовых файлов или в маловероятном случае есть ZWNBSP в середине файла), вы можете использовать grep:

 fgrep -rl `echo -ne '\xef\xbb\xbf'` . 

Я бы использовал что-то вроде:

 grep -orHbm1 "^`echo -ne '\xef\xbb\xbf'`" . | sed '/:0:/!d;s/:0:.*//' 

Это гарантирует, что спецификация будет начинаться с первого байта файла.

Вы можете использовать grep чтобы найти их и Perl, чтобы вырезать их так:

 grep -rl $'\xEF\xBB\xBF' . | xargs perl -i -pe 's{\xEF\xBB\xBF}{}' 

Для пользователя Windows см. Это (хороший PHP-скрипт для поиска BOM в вашем проекте).

Решение overkill для этого – phptags (не инструмент vi с тем же именем), который специально ищет PHP-скрипты:

 phptags --warn ./ 

Выведет что-то вроде:

 ./invalid.php: TRAILING whitespace ("?>\n") ./invalid.php: UTF-8 BOM alone ("\xEF\xBB\xBF") 

И режим --whitespace автоматически исправляет такие проблемы (рекурсивно, но утверждает, что он только перезаписывает скрипты .php).

 find -type f -print0 | xargs -0 grep -l `printf '^\xef\xbb\xbf'` | sed 's/^/found BOM in: /' 
  • find -print0 помещает нуль \ 0 между каждым именем файла вместо использования новых строк
  • xargs -0 ожидает нулевых аргументов, а не разделенных строк
  • grep -l перечисляет файлы, соответствующие регулярному выражению
  • ^\xeff\xbb\xbf выражение ^\xeff\xbb\xbf не совсем корректно, так как оно будет соответствовать файлам не-BOMed UTF-8, если они имеют нулевые пространства ширины в начале строки

Я использовал это, чтобы исправить только файлы JavaScript:

 find . -iname *.js -type f -exec sed 's/^\xEF\xBB\xBF//' -i.bak {} \; -exec rm {}.bak \; 

Если вы ищете файлы UTF, команда файла работает. Он расскажет вам, что такое кодировка файла. Если есть какие-либо символы, отличные от ASCII, он будет иметь UTF.

 file *.php | grep UTF 

Однако это не будет работать рекурсивно. Возможно, вы можете придумать какую-нибудь причудливую команду, чтобы сделать ее рекурсивной, но я просто обыскал каждый уровень индивидуально, как показано ниже, до тех пор, пока не закончится уровень.

 file */*.php | grep UTF