Замените длинную строку командой sed: Ошибка «Список аргументов слишком длинный»

Замените длинную строку командой sed: Ошибка «Список аргументов слишком длинный»

Я пытаюсь выполнить эту команду

sed -i -e "s/BASE_64/$BASE_64/" FILE_NAME

где $BASE_64— это представление содержимого файла в формате base 64.

sedвыдает ошибку, так как строка слишком длинная.

Список аргументов слишком длинный

Как можно избежать этой ошибки?

решение1

Вы всегда можете сделать (раз уж вы используете GNU sed( -i)):

sed -i -f - FILE_NAME << EOF
s/BASE_64/$BASE_64/g
EOF

-f -указывает sedна необходимость чтения скрипта sed из stdin.

Если вы хотите повторно использовать один и тот же скрипт для нескольких файлов в Linux (и только в Linux) с оболочкой вроде zsh, kshи bashверсией до 5.0, которая реализует here документы с временными файлами (в отличие от каналов вроде dashили yash(или bash5.1+) для относительно небольших heredocs и все еще с GNU sed, вы можете сделать следующее:

find . -name '*.conf' -exec sed -i -f /dev/stdin {} + << EOF
s/BASE_64/$BASE_64/g
EOF

В Linux (и только в Linux и Cygwin) /dev/stdinэто не означаетстандартный вводтаким же образом -. Вместо этого это символическая ссылка на файл, открытый на stdin, поэтому каждый раз sedпри его открытии он открывает файл заново с самого начала. Приведенная выше команда будет работать нормально в других системах (в которых есть /dev/stdin) или с оболочками, которые реализуют here-documents с каналами, но только если файлов достаточно мало, confчто sedвызывается только один раз. При повторном вызове в системах, отличных от Linux/Cygwin, например с -f -, /dev/stdinбудет отображаться пустым, поскольку он уже был прочитан первым вызовом.

busybox sedтакже поддерживает -iтак же, как GNU sed, но не поддерживает . Так что вам в любом случае -f -следует использовать там. С FreeBSD используйте:-f /dev/stdinsed

sed -i '' -f /dev/stdin FILE_NAME << EOF
s/BASE_64/$BASE_64/g
EOF

решение2

Сначала сохраните данные в кодировке base64 в файле с именем, например, base64.txt.

Например:

base64 < originalfile > base64.txt

Затем:

printf '%s\n' '/BASE64/r base64.txt' 1 '/BASE64/d' w | ed FILENAME

Это используется edдля поиска FILENAMEстроки, содержащей строку BASE64, вставки содержимого base64.txtпосле этой строки, возврата к первой строке, затем BASE64повторного поиска строки со строкой и удаления ее. wКоманда в edсохраняет измененный файл.

решение3

Другой вариант — заменить sedи edсохранить ваши команды в файле. Например, если вы создаете ed_cmdsсо следующим содержимым:

%s/BASE_64/<expanded variable>/g
w
q

вы могли бы тогда бежать

< ed_cmds ed FILE_NAME

и он внесет нужные вам изменения, поэтому вместо настройки $BASE_64вам придется создать командный файл ed.

Эд Объяснение

  • %означает применить команду к каждой строке файла
  • s/pat1/pat2/gзаменяет вхождения pat1на pat2и gв конце заставляет это делать для каждого совпадения в строке, а не только для первого
  • wзаписать изменения на диск
  • qвыйти (что в любом случае произошло бы, когда бы он достиг EOF)

Конечно, вы можете поместить свои sedкоманды в файл и использовать -fего, но если вы делаете это и хотите изменить файл на месте, вы можете использовать его edвместо создания временного файла и его перемещения, как sed -iэто делается.

решение4

В итоге я поместил sedинструкции в файл

SEDCOMMANDS=`tempfile`

и позвонил

sed -f "$SEDCOMMANDS" -- "$FILE_NAME"

Это хорошо, если вы не используете sed -i. Если вы хотите редактировать файл на месте, следуйтеhttps://unix.stackexchange.com/a/284188/149867и поместите эквивалентные edинструкции в файл, за которым следуют wи q.

Связанный контент