Самый эффективный способ изменить 1 строку в файле

В Linux Mint 19 (Ubuntu 18.04 )просто установите vdpau -драйвер -все решит эту проблему.

Failed to open VDPAU backend libvdpau_radeonsi.so: cannot open shared object file: No such file or directory

Решение:

$ apt install vdpau-driver-all
5
13.08.2020, 23:09
5 ответов

Оптимизация заключалась бы в использовании {} +вместо {} \;.

find. -type f -exec sed -i '1s|^#!/bin/bash|#!/bin/sh|' {} +

Вместо вызова одного процесса sed для каждого найденного файла вы предоставляете файлы в качестве аргументов одному процессу sed.

Спецификация POSIX find на{} +(жирным шрифтом):

If the primary expression is punctuated by a <plus-sign>, the primary shall always evaluate as true, and the pathnames for which the primary is evaluated shall be aggregated into sets. The utility utility_name shall be invoked once for each set of aggregated pathnames.

7
18.03.2021, 23:12

Да, sed -iчитает и перезаписывает файл полностью, а так как длина строки меняется, то приходится, так как перемещает позиции всех остальных строк.

...но в этом случае длину строки менять не нужно. Вместо этого мы можем заменить строку hashbang на #!/bin/sh␣␣с двумя пробелами в конце. ОС удалит их при разборе строки hashbang. (В качестве альтернативы можно использовать два символа новой строки или символ новой строки + решётка, оба из которых создают дополнительные строки, которые оболочка в конечном итоге проигнорирует.)

Все, что нам нужно сделать, это открыть файл для записи с самого начала, не усекая его. Обычные перенаправления >и >>не могут этого сделать, но в Bash, кажется, работает перенаправление чтения -записи <>:

.
echo '#!/bin/sh  ' 1<> foo.sh

или используяdd(это должны быть стандартные параметры POSIX):

echo '#!/bin/sh  ' | dd of=foo.sh conv=notrunc

Обратите внимание, что, строго говоря, оба они также переписывают новую строку в конце строки, но это не имеет значения.

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

19
18.03.2021, 23:12

Файлы представляют собой один длинный непрерывный диапазон байтов. Ваша замена bashна shпо существу потребует удаления двух байтов (при условии UTF -8 или аналогичного ), которые составляют ba. В файлах не может быть дырок, поэтому все, что начинается с sh, придется записывать в файл на два байта раньше.

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

Существуют способы замены байтов в файле, например, невинными пробелами, если формат позволяет это без перезаписи всего файла, см. принятый ответ.

2
18.03.2021, 23:12

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

Эту проблему можно решить с помощью некоторых хитростей, используя такой инструмент, как dd(, или используя mmap()или fseek()в C )для изменения фрагментов в файле по одному. Например, если вы хотите добавить 2 символа в начало файла, вы можете работать в обратном направлении с конца, сдвигая все вперед на 2 символа.

Урок здесь в том, что в UNIX файлы часто обрабатываются как "потоки", проходящие через программу, но их также можно рассматривать как байтовые массивы, которые можно редактировать -на месте.

2
18.03.2021, 23:12

Я бы сделал:

#! /bin/zsh -
LC_ALL=C # work with bytes instead of characters.
shebang_to_replace=$'#!/bin/bash\n'
       new_shebang=$'#!/bin/sh -\n'

length=$#shebang_to_replace

ret=0
for file in **/*(N.L+$((length - 1)));do
  if
    read -u0 -k $length shebang < $file &&
      [[ $shebang = $shebang_to_replace ]]
  then
    print -rn -- $new_shebang 1<> $file || ret=$?
  fi
done
exit $ret

Подобно подходу @ilkkachu , файл перезаписывается строкой точно такого же размера. Различия:

  • мы игнорируем скрытые файлы и файлы в скрытых каталогах (подумайте .gitодин например )так как маловероятно, что вы захотите учитывать те (которые вы использовали find./*которые пропустили бы скрытые файлы и каталоги текущего каталога, но не подкаталогов ). Добавьте квалификатор Dglob, если они вам нужны.
  • мы не утруждаем себя просмотром файлов, которые недостаточно велики для хранения оригинального шебанга для замены (мы используем .как эквивалент -type f, поэтому мы уже извлекаем информацию об индексе из файл, так что мы могли бы также проверить размер там ).
  • мы на самом деле проверяем, что файл начинается с правильного шебанга для замены, считывая столько байтов, сколько необходимо (здесь должно быть zshтак как другие оболочки не могут работать с произвольными значениями байтов ).
  • мы используем #!/bin/sh -в качестве замены, которая является правильным шебангом для /bin/shскриптов(#!/bin/bash -кстати, будет правильным шебангом для /bin/bashскриптов ). См. Почему " -" в " #! /bin/sh -" шебанге? для получения подробной информации.

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

В любом случае, он заменяет только шебанги, которые точно #!/bin/bash, а не другие шебанги, которые используют bashв качестве интерпретатора, например #! /bin/bash, #! /bin/bash -Oextglob, #! /usr/bin/env bash, #! /bin/bash -efu. Для них вам нужно решить, что делать. -efu— это опции sh, но -Oextglobне имеет, например, эквивалента sh.

Вы можете расширить его для поддержки самых простых случаев, таких как:

#! /bin/zsh -
LC_ALL=C # work with bytes instead of characters.
zmodload zsh/system || exit

minlength=11 # length of "#!/bin/bash"
maxlength=1024 # arbitrary here.

ret=0
for file in **/*(N.L+$minlength);do
  if
    sysread -s $maxlength buf < $file &&
      [[ $buf =~ $'(^#![\t ]*((/usr)?/bin/env[ \t]+bash|/bin/bash)([ \t]+-([aCefux]*))?[ \t]*)\n' ]]
  then
    shebang=$match[1] newshebang="#!/bin/sh -$match[5]"
    print -r -- ${(r[$#shebang])newshebang} 1<> $file || ret=$?
  fi
done
exit $ret

Здесь разрешен ряд различных шебангов с рядом поддерживаемых опций, которые воспроизводятся в новом /bin/shшебанге, дополненном справа -(с флагом расширения параметра r[length])до того же размера. как оригинал.

5
18.03.2021, 23:12

Теги

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