Как игнорировать файлы только для чтения с помощью `perl -i`?

Переключатель Perls -i появляется, чтобы изменить файлы только для чтения:

$ echo 'foobar' > tmp.txt
$ chmod -w tmp.txt
$ perl -pi -w -e 's/foobar/FOOBAR/' tmp.txt
$ cat tmp.txt
FOOBAR

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

$ echo 'barbaz' > tmp.txt
-bash: tmp.txt: Permission denied

Почему Perl модифицирует файлы только для чтения (и как?) и, что самое главное, как я могу заставить Perl не делать этого?

Единственный информативный ресурс, который я могу найти в этом разделе, находится в часто задаваемых вопросах Perl:

Разрешения на файл говорят, что может случиться с данными в этом файле.... Если вы попытаетесь записать в файл, разрешения файла определяют, разрешено ли вам.

В конечном итоге кажется, что он говорит, что он не должен писать на него, поскольку файловая система говорит, что вы не можете.

Ответ 1

Фильтр @ARGV в блоке BEGIN:

perl -pi -e 'BEGIN{@ARGV=grep{-w $_}@ARGV} s/foobar/FOOBAR/' files

Теперь, если ни один из файлов в командной строке не доступен для записи, @ARGV будет пустым, а дескриптор файла ARGV попытается прочитать из STDIN. Я могу думать о двух способах избежать этого:

  • Закройте STDIN в блоке BEGIN тоже

    perl -pi -e 'BEGIN{close STDIN;@ARGV=grep{-w $_}@ARGV}s/foobar/FOOBAR/' files
    
  • Всегда вызывайте этот однострочный перенаправляющий ввод из /dev/null

    perl -pi -e 'BEGIN{@ARGV=grep{-w $_}@ARGV}s/foobar/FOOBAR/' files < /dev/null
    

Ответ 2

Смотрите документацию в perlrun:

переименование входного файла, открытие выходного файла по имени оригинала и выбор этого выходного файла в качестве параметров по умолчанию для операторов print()

(...)

Для обсуждения вопросов, связанных с разрешениями файлов и -i, см. "Почему Perl позволяет мне удалить файлы только для чтения? Почему -i clobber защищает файлы? Разве это не ошибка в Perl?" В perlfaq5.

Ответ 3

Из perlrun:

-i
указывает, что файлы, обработанные конструкцией < > , редактируются на месте. Он делает это, переименовывая входной файл, открывая выходной файл по исходному имени и выбирая этот выходной файл как значение по умолчанию для операторов print().

Таким образом, он действительно не изменяет файл. Он перемещает файл в сторону (для этого требуются права на запись в записи, а не права на запись файла), а затем создает новый со старым именем.

как я могу заставить Perl не делать этого?

Я не думаю, что вы можете использовать -i.