Shell - Grava o conteúdo da variável em um arquivo

95

Eu gostaria de copiar o conteúdo de uma variável (aqui chamada var) em um arquivo.

O nome do arquivo é armazenado em outra variável destfile.

Estou tendo problemas para fazer isso. Aqui está o que tentei:

cp $var $destfile

Eu também tentei a mesma coisa com o comando dd ... Obviamente o shell pensou que $varse referia a um diretório e então me disse que o diretório não foi encontrado.

Como faço para contornar isso?

user1546083
fonte
2
Melhore sua pergunta postando algum código formatado corretamente que mostre como você está preenchendo suas variáveis ​​e todas as mensagens de erro relevantes exatamente como aparecem.
Todd A. Jacobs
2
O que você quer dizer com "copiar o conteúdo de uma variável" para um diretório? Não $varespecificar um nome de arquivo ou algum texto que devem ser gravados em um arquivo? Se especificar um texto, qual é o nome do arquivo no qual você gostaria de escrever esse conteúdo?
jahroy
$ var contém o texto que desejo copiar e o arquivo no qual deve ser gravado é definido pelo usuário, portanto, estou usando uma variável em primeiro lugar.
user1546083
1
Talvez $destdirdeva ser nomeado $destfilepara não enganar ... O nome $destdirsugere que ele especifica um diretório em vez de um arquivo. Isso tornaria toda a sua questão direta e fácil de entender.
jahroy

Respostas:

145

Use o echocomando:

var="text to append";
destdir=/some/directory/path/filename

if [ -f "$destdir" ]
then 
    echo "$var" > "$destdir"
fi

Os iftestes que $destdirrepresentam um arquivo.

O >anexa o texto após truncar o arquivo. Se você deseja apenas anexar o texto $varao conteúdo existente do arquivo, use >>:

echo "$var" >> "$destdir"

O cpcomando é usado para copiar arquivos (para arquivos), não para gravar texto em um arquivo.

pb2q
fonte
4
Precisa de mais aspas - agora, qualquer execução de espaço em branco dentro do valor da variável será convertida em um único espaço, as expressões glob serão expandidas, etc.
Charles Duffy
2
Uma outra coisa - você precisa de um espaço entre a cotação de fechamento eo ]no "$destdir"].
Charles Duffy
3
echotambém adiciona uma nova linha à sua variável.
Ben Dilts
6
Isso falha se $varfor -e text to append, e realmente não escreve o-e
Eric,
1
Por echo $vardepender do shell para expandir sua variável, ele não funciona muito bem com coisas como espaço em branco e caracteres especiais. Você pode usar perl -e 'print($ENV{var})', em vez disso, e ele produzirá precisamente o valor da variável.
Blake Mitchell
38

echotem o problema de que se varcontiver algo parecido -e, será interpretado como um flag. Outra opção é printf, mas printf "$var" > "$destdir"irá expandir quaisquer caracteres de escape na variável, portanto, se a variável contiver barras invertidas, o conteúdo do arquivo não corresponderá. No entanto, como printfapenas interpreta barras invertidas como escapes na string de formato, você pode usar o %sespecificador de formato para armazenar o conteúdo exato da variável no arquivo de destino:

printf "%s" "$var" > "$destdir"

Trebawa
fonte
1
printf também é bom se você tiver novas linhas na variável string, como de aspas triplas ou heredoc. echo não lida bem com as novas linhas.
beeflobill
@beeflobill pode explicar como "echo não lida bem com as novas linhas". A única coisa que vi é que echo adiciona uma nova linha. O que torna echo "$var" > destfileerrado.
SensorSmith
@SensorSmith Em minhas experiências, vejo que quando a string tem "\ n", aquele eco imprime um caractere de nova linha. Mas, se a string tiver um caractere de nova linha real, o eco não o imprimirá. Não sei por quê.
beeflobill
1
Basicamente, um problema de portabilidade (e confiabilidade). unix.stackexchange.com/a/65819… ou para os mortais entre nós: printfé melhor, siga em frente.
user3342816
29

Nenhuma das respostas acima funciona se sua variável:

  • começa com -e
  • começa com -n
  • começa com -E
  • contém um \seguido por umn
  • não deve ter uma nova linha extra anexada após ele

e assim eles não podem ser confiados para conteúdos de string arbitrários.

No bash, você pode usar "here strings" como:

cat <<< "$var" > "$destdir"

Conforme observado no comentário abaixo, a resposta de @Trebawa (formulada na mesma sala que a minha!) Usando printfé uma abordagem melhor.

Eric
fonte
5
Pelo que eu posso dizer, cat sempre inserirá uma nova linha no final do arquivo, independentemente de não haver uma nova linha no final da variável (embora isso seja indiscutivelmente uma coisa boa na maioria dos casos). A resposta usando printf parece evitar a inserção de uma nova linha à direita.
Ash
@Ash outra vantagem de printfover caté que o primeiro é um shell embutido que sempre executa mais rápido do que um binário externo.
Géza Török
7

Se bem entendi, você deseja copiar $varem um arquivo (se for uma string).

echo $var > $destdir
qwertz
fonte
Assim que se faz. Usar o cpcomando fará com que o shell interprete o primeiro argumento como o nome de um arquivo ou diretório.
jahroy
5
Se você não colocar $varentre aspas, o conteúdo do arquivo não é 100% igual ao conteúdo de $ var em alguns casos. Por exemplo, ao "ecoar" vars que contêm chaves RSA, você obtém uma chave inválida no arquivo.
srigi
6
Falha se $varcontiver espaços ou-e
Eric
1

Quando você diz "copiar o conteúdo de uma variável", essa variável contém um nome de arquivo ou contém o nome de um arquivo?

Estou supondo por sua pergunta que $varcontém o conteúdo que você deseja copiar para o arquivo:

$ echo "$var" > "$destdir"

Isso irá ecoar o valor de $ var em um arquivo chamado $ destdir. Observe as citações. Muito importante ter "$ var" entre aspas. Também para "$ destdir" se houver um espaço no nome. Para anexar:

$ echo "$var" >> "$destdir"
David W.
fonte
3
Falha se varcontiver-e
Eric
1
Passar um hífen duplo como primeiro argumento para echo encerrar sua lista de opções, assim resolve o problema levantado por @Eric:echo -- "$var" >> "$destfile"
Géza Török
1

Todos os itens acima funcionam, mas também têm que solucionar um problema (escapes e caracteres especiais) que não precisa ocorrer em primeiro lugar: caracteres especiais quando a variável é expandida pelo shell. Só não faça isso (expansão de variável) em primeiro lugar. Use a variável diretamente, sem expansão.

Além disso, se sua variável contém um segredo e você deseja copiar esse segredo em um arquivo, você pode querer não ter expansão na linha de comando, pois o rastreamento / eco de comando dos comandos do shell pode revelar o segredo. Significa que todas as respostas que usam $varna linha de comando podem ter um risco potencial de segurança, expondo o conteúdo da variável para rastreamento e registro do shell.

Usa isto:

printenv var >file

Isso significa que, no caso da questão do OP:

printenv var >"$destfile"
Christian Hujer
fonte