Альтернатива sed -i, которая не записывает временные файлы

Сегодня я столкнулся с этой проблемой на своем ноутбуке Lenovo Yoga 730 с диском ADATA NVMe 512G. У меня были ошибки при запуске mkfs.ext4, но он завершился. Как только я попытался смонтировать раздел, я получил ту же ошибку, что и описанная.

Я попробовал версию Arch от мая 2019 г., и проблем не возникло. Кажется, проблема появилась в выпуске за июнь 2019 года. Используя ISO-образ от мая 2019 года, я смог успешно установить Arch на свой диск NVMe. Версия ядра после установки: 5.2.4 -arch1 -1 -ARCH.

0
30.08.2021, 10:26
2 ответа

Ваша проблема не в том, что sed -iсоздает много временных файлов, а в том, что вы запускаете его много раз с одним и тем же входным файлом, и каждый из них создает временный файл для вывода, как показано в strace:

execve("/bin/sed", ["sed", "-i", "-e", "", "/tmp/foo"], 0x7fff10da5288 /* 36 vars */) = 0
openat(AT_FDCWD, "/tmp/foo", O_RDONLY)  = 3
openat(AT_FDCWD, "/tmp/sedVdjaBk", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
rename("/tmp/sedVdjaBk", "/tmp/foo")    = 0
+++ exited with 0 +++

Решение состоит в том, чтобы запустить sed -iтолько один раз.

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

sed -e 's!.*!s/install, element = &, at=/install, element = &, at= -0.001 +/g!"

(Возможно, мы могли бы улучшить это, если бы входной файл содержал значимые символы регулярного выражения -, например. s/install, element = &, at=/\& -0.001 +/g, но это выходит за рамки данного вопроса ).

Протестируйте это, чтобы убедиться, что полученный скрипт вас устраивает.

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

sed -e 's!.*!s/install, element = &, at=/install, element = &, at= -0.001 +/g!' \
    shiftLeft.txt |
sed -f - -i processedFiles/layoutDB.seq

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


¹ Поскольку мы используем , мы можем использовать подстановку процесса:

sed -f <(sed -e 's!.*!s/install, element = &, at=/install, element = &, at= -0.001 +/g!' shiftLeft.txt) \
    -i processedFiles/layoutDB.seq

В стандартной оболочке нам нужно было бы захватить преобразованный текст в виде строки и предоставить его в виде командного -строкового скрипта:

sed -e "$(sed -e 's!.*!s/install, element = &, at=/install, element = &, at= -0.001 +/g!' shiftLeft.txt)" \
    -i processedFiles/layoutDB.seq
4
30.08.2021, 13:00

Не вызывайте повторно sed в цикле оболочки, просто вызовите awk один раз, например. (не проверено, так как вы не предоставили образец ввода/вывода для тестирования )с использованием GNU awk для редактирования «на месте» и 3-го аргумента для соответствия():

awk -i inplace '
    NR==FNR { lines[$0] }
    (FNR>NR) && match($0,/(.*install, element = )([^,]+)(, at=)/,a) && (a[2] in lines) {
        $0 = a[0] " -0.001 +"
    }
    { print }
' shiftLeft.txt processedFiles/layoutDB.seq

Может быть лучший способ сделать это в зависимости от того, как выглядит ваш ввод/вывод.

3
30.08.2021, 17:33

Теги

Похожие вопросы