Substitua uma cadeia longa pelo comando sed: Argument list too long error

7

Estou tentando executar este comando

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

em que $BASE_64 é uma representação base 64 de um conteúdo de arquivo.

sed me dá um erro porque a string é muito longa.

Argument list too long

Como é possível evitar esse erro?

    
por Lorenzo B 19.05.2016 / 15:15

5 respostas

4

Primeiro, salve os dados codificados em base64 em um arquivo chamado, por exemplo, base64.txt .

Por exemplo:

base64 < originalfile > base64.txt

Então:

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

Isso usa ed para pesquisar em FILENAME para uma linha que contém a string BASE64 , insira o conteúdo de base64.txt depois dessa linha, volte para a primeira linha e, em seguida, procure a linha com a string BASE64 novamente e exclua-o. O comando w em ed salva o arquivo modificado.

    
por 20.05.2016 / 05:42
4

Outra opção seria substituir sed por ed e armazenar seus comandos em um arquivo. Por exemplo, se você criar ed_cmds com o seguinte conteúdo:

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

você pode então executar

< ed_cmds ed FILE_NAME

e faria as alterações desejadas, portanto, em vez de definir $BASE_64 , você criaria o arquivo de comando ed.

Ed Explicação

  • % significa aplicar o comando a cada linha do arquivo
  • s/pat1/pat2/g substitui as ocorrências de pat1 com pat2 e g no final faz com que seja para cada correspondência na linha, não apenas na primeira
  • w escreve as alterações no disco
  • q quit (o que aconteceria quando obtivesse EOF)

É claro, você poderia colocar seus comandos sed em um arquivo e usar -f também, mas se você estiver fazendo isso e quiser modificar o arquivo no lugar, também pode usar ed de criar um arquivo temporário e movê-lo como sed -i .

    
por 19.05.2016 / 16:18
3

Você sempre pode fazer (já que você está usando o GNU sed já ( -i )):

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

-f - diz sed para ler o script sed do stdin.

Se você quiser reutilizar o mesmo script para vários arquivos, no Linux (e somente no Linux), com um shell como bash , zsh , ksh que implementa aqui documentos com arquivos temporários (em oposição a pipes como dash ou yash ) e ainda com o GNU sed , você poderia fazer:

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

No Linux (e no Linux apenas), /dev/stdin não significa stdin da mesma maneira que - . Em vez disso, é um link simbólico para o arquivo aberto no stdin, então cada vez que sed abrir, ele abrirá o arquivo novamente desde o início. O comando acima funcionaria bem em outros sistemas (que possuem /dev/stdin ) ou com shells que implementam here-documents com pipes, mas somente se houver poucos arquivos conf suficientes para que sed seja chamado apenas uma vez. Quando chamado pela segunda vez, em sistemas não Linux, como com -f - , /dev/stdin apareceria vazio porque já foi lido pela primeira chamada.

busybox sed também suporta -i da mesma forma que o GNU sed , mas não suporta -f - . Então você quer usar -f /dev/stdin em qualquer caso. Com FreeBSD sed , use:

sed -i '' -f /dev/stdin FILE_NAME << EOF
s/BASE_64/$BASE_64/g
EOF
    
por 26.02.2017 / 09:32
2

O tamanho da representação Base64 do arquivo ($ BASE_64) é muito longo e excede o tamanho máximo do argumento. Você deve conseguir ver esse limite para o seu sistema executando

getconf ARG_MAX

Você precisa aumentar o tamanho do valor ARG_MAX . Mas acho que se o arquivo for muito grande, você terá que usar uma abordagem diferente para fazer essa substituição. Se um script Python faria isso por você, eu tentaria com isso também.

    
por 19.05.2016 / 15:29
1

Acabei colocando as instruções sed em um arquivo

SEDCOMMANDS='tempfile'

e chamado

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

Isso é bom se você não usar sed -i . Se você quiser editar o arquivo, siga o link e coloque as instruções equivalentes de ed em um arquivo, seguido por w e q .

    
por 26.02.2017 / 07:08