
В настоящее время я использую следующееупрощенная командакудалить конечные пробелыидобавить новую строку в конец файлагде необходимо:
find . -type f -exec sed -i -e 's/[ \t]\+\(\r\?\)$/\1/;$a\' {} \+
Как вы быстро увидите, здесь есть две проблемы: это изменитсядвоичные файлыи он добавит новую строку в конец файлов с␍␊ разделители строк. Эти изменения легко отменить или пропустить при фиксации git gui
или чем-то подобном, но я хотел бы минимизировать* количество откатов. Для этого:
Есть ли способ пропуститьвесьфайл еслилюбойстрока соответствует регулярному выражению в sed
?
* Я знаю, что могут быть двоичные файлы без символов ␀, и могут быть файлы с намеренно смешанными символами новой строки или ␀. Но я ищу решение, которое требует минимального человеческого вмешательства. Ямогможно было бы перечислить все расширения файлов, с которыми я хотел бы работать, но это был бы очень длинный список, который пришлось бы постоянно просматривать, и из-за конфликтов имен все равно были бы шансы, что в него проскользнут двоичные файлы.
Сложныйобходной путь:
while IFS= read -r -d '' -u 9
do
if [[ "$(file -bs --mime-type -- "$REPLY")" = text/* ]]
then
sed -i -e 's/[ \t]\+\(\r\?\)$/\1/;$a\' -- "$REPLY"
else
echo "Skipping $REPLY" >&2
fi
done 9< <(find . -type f -print0)
решение1
Если вы доверяете git
точке зрения на то, что является двоичным файлом, а что нет, вы можете использовать git grep
для получения списка недвоичных файлов. Предполагая, t.cpp
что это текстовый файл, а ls
это двоичный файл, оба проверены в:
$ ls
t.cpp ls
$ git grep -I --name-only -e ''
t.cpp
Опция -I
означает:
-I
Не сопоставляйте шаблон в двоичных файлах.
Чтобы объединить это с вашим sed
выражением:
$ git grep -I --name-only -z -e '' | \
xargs -0 sed -i.bk -e 's/[ \t]\+\(\r\?\)$/\1/;$a\'
( -z
/ xargs -0
для помощи со странными именами файлов.)
Ознакомьтесь со git grep
страницей руководства для получения информации о других полезных опциях ( --no-index
или --cached
возможной помощи в зависимости от того, с каким именно набором файлов вы хотите работать).
решение2
Есть ли способ пропустить весь файл, если какая-либо строка соответствует регулярному выражению в sed?
Да, есть.
# test case for skipping file if a sed regex match succeeds
echo 'Hello, world!' > hello_world.txt
cat hello_world.txt
ls -li hello_world.txt
sed -i -e '/.*Hello.*/{q;}; s/world/WORLD/g' hello_world.txt # skips file
sed -i -e '/.*HeLLo.*/{q;}; s/world/WORLD/g' hello_world.txt
решение3
Вот скрипт Perl, который перебирает свои аргументы (которые должны быть именами файлов) и добавляет новую строку к каждому файлу, который не заканчивается новой строкой. Файлы, содержащие нулевой байт, пропускаются. Файлы, которые уже заканчиваются новой строкой, не изменяются. Файлы, содержащие CR, получают CRLF, другие получают только LF. Не проверено.
#!/usr/bin/env perl
foreach my $f (@ARGV) {
open F, "<", $f or die;
my $last = undef;
my $cr = 0;
while (<>) {if (/\0/) {undef $last; break} $last = $_; ++$cr if /\r$/}
close F;
if (defined $last && $last !~ /\n\Z/) {
open F, ">>", $f or die;
print($cr ? "\r\n" : "\n");
close F or die;
}
}