заменить на месте, используя perl измененную программную ссылку / символическую ссылку на статический файл - PullRequest
0 голосов
/ 02 ноября 2018

С учетом следующей команды:

git ls-files | xargs perl -i -pe 's/SEARCHTERM/REPLACETERM/g'

Все выходные данные в perl (из git ls-файлов), которые были символическими ссылками, теперь копируют целевых файлов.

У меня есть два вопроса:

1) Мне кажется, я смутно понимаю, почему это произошло, но только смутно. Может кто-нибудь объяснить подробно? И предложить лучший механизм, чтобы избежать этого? Ожидаемое поведение будет состоять в том, что цели символической ссылки будут целью чтения И записи, а не только чтения.

2) Есть ли лучший общий подход для поиска и замены в локальной ветке git?

Стоит заметить, что мой bash довольно элементарен, и xargs - это просто мой переход по умолчанию, когда я хочу убедиться, что содержимое файлов обрабатывается, а не список файлов. Не используется ни по какой другой причине, кроме этой.

Ответы [ 5 ]

0 голосов
/ 04 ноября 2018

Все, что вам нужно, это

git ls-files | xargs readlink -e | xargs perl -i -pe'...'

Вы также можете расширить ссылки в Perl.

git ls-files | xargs perl -i -pe'BEGIN { @ARGV = map readlink($_) // $_, @ARGV } ...'
0 голосов
/ 03 ноября 2018

Другая опция Perl:

git ls-files | xargs perl -MPath::Tiny -Mutf8 -E'
  path($_)->realpath->edit_lines_utf8(sub { s/SEARCHTERM/REPLACETERM/g })
  for @ARGV'

Или без xargs, просто прочитайте имена файлов из STDIN:

git ls-files | perl -MPath::Tiny -Mutf8 -E'
  path($_)->realpath->edit_lines_utf8(sub { s/SEARCHTERM/REPLACETERM/g })
  for map { chomp; $_ } readline'

realpath гарантирует, что вы всегда работаете с целью символической ссылки, а edit_lines по сути является реализацией Path :: Tiny опции -i. Использование edit_lines_utf8 и -Mutf8 означает, что ваш исходный код (условия поиска и замены) и содержимое файла будут декодированы из UTF-8 во время выполнения поиска / замены, что обычно полезно (но если ваши файлы не Кодировать UTF-8, удалить -Mutf8 и использовать edit_lines). Вы также можете отфильтровать нетекстовые файлы на основе эвристики -T , добавив grep { -T } после for.

В качестве бонуса, edit_lines всегда будет выводить в новый файл, а затем переименовывать его поверх оригинала, что безопаснее, чем копирование исходного файла, чего -i не делал до Perl 5.28 .

CAVEAT: Path :: Tiny будет устанавливать разрешения для всех файлов, которые он редактирует, основываясь на вашем текущем umask, а не на существующих разрешениях; Я открыл вопрос , чтобы проверить, не считается ли это ошибкой.

0 голосов
/ 02 ноября 2018

сказано в perlrun

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

Так что нельзя сделать это с -i.

Вот еще один способ с Perl (как помечено - даже если есть чистое решение с sed)

Я использую файлы a.txt, b.txt, их символические ссылки (ln -s a.txt ln_a.txt и т. Д.) И c.txt (и любой контент подходит для этого теста), а также список имен ссылок и c.txt в файле

ln_a.txt ln_b.txt c.txt    # file "input_list.txt"

где имена файлов / ссылок в input_list.txt могут быть разделены пробелами или переводами строки.

Затем откройте временный выходной файл в первой строке каждого входного файла и запишите в него каждую обработанную строку. Как только будет достигнут конец входного файла, переименуйте этот временный вывод в его входной файл или в его цель, если это ссылка. Таким образом, для каждого входного файла перезаписать файл или его цель, если ссылка, с выходным файлом.

cat input_list.txt | xargs perl -MPath::Tiny -ne'
    if ($.==1) { $tf = $ARGV."_tmp.$$"; $fh = path($tf)->openw };
    s/(\w+)/$1-NEW/; 
    print $fh $_; 
    if (eof) { close ARGV; rename $tf, (-l $ARGV ? readlink $ARGV : $ARGV) }
'

Это изменяет содержание целей и оставляет ссылки в покое. Это работает и для обычных файлов.

Временное имя выходного файла (filename_tmp.$$) может быть правильно задано с помощью File::Temp или, скорее, с помощью Path :: Tiny :: tempfile , так как этот модуль уже используется.

переименовать , вероятно, следует изменить на move с File :: Copy , для переносимости.

Используемое eof проверяет, не исчерпан ли файл для каждого входного файла, после чего выходной файл переименовывается во входной файл или в его цель. -l является оператором проверки файлов , который проверяет, является ли файл в наличии символической ссылкой, и если это так, то readlink разрешает ссылку.

Безопасно rename входной файл или цель в это время, так как он был прочитан и обработан.

$ ARGV - это имя обработанного в данный момент файла, и ARGV - дескриптор файла для него.

Явное close ARGV сбрасывает счетчик строк, чтобы мы могли открывать временные выходные данные в начале каждого нового входного файла, проверяя счетчик номера строки $. против 1.

0 голосов
/ 02 ноября 2018

Моим первоначальным решением этой проблемы было просто позволить символическим ссылкам заточиться, а затем запустить:

git status --porcelain | awk '{if ($1 == "T"){print $2}}' | xargs git checkout

Это действительно хорошо для различных инструментов, которые могут заглушить символические ссылки, если они оказываются случайными и не имеют никакого отношения к поиску.

Ссылка здесь имеет несколько интересных идей: https://unix.stackexchange.com/questions/9318/is-there-a-way-to-make-perl-i-not-clobber-symlinks

Ответ Здима - лучшая реализация одного из них, я думаю. Хотя и немного волосатый.

Другой ответ по этой ссылке, использующий sponge, работает, но создает очень сложный канал xargs. Кроме того, я считаю, что требуется использование xargs -n1, что является катастрофически медленным способом запуска perl в больших файловых системах. Так что это не пойдет.

И ответ Рафаэля (просто используйте sed), вероятно ... самый разумный способ решить эту проблему:)

0 голосов
/ 02 ноября 2018

Если вы не против использования sed, обернитесь:

git ls-files | xargs -I{} -P4 sed --follow-symlinks -i'' 's/SEARCHTERM/REPLACETERM/g' {} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...