Shell: escribe el contenido de la variable en un archivo

95

Me gustaría copiar el contenido de una variable (aquí llamada var) en un archivo.

El nombre del archivo se almacena en otra variable destfile.

Tengo problemas para hacer esto. Esto es lo que probé:

cp $var $destfile

También intenté lo mismo con el comando dd ... Obviamente, el shell pensó que $varse refería a un directorio y me dijo que no se podía encontrar el directorio.

¿Cómo puedo solucionar esto?

usuario1546083
fuente
2
Mejore su pregunta publicando un código con el formato adecuado que muestre cómo está completando sus variables y todos los mensajes de error relevantes exactamente como aparecen.
Todd A. Jacobs
2
¿Qué quiere decir "copiar el contenido de una variable" en un directorio? ¿ $varEspecifica un nombre de archivo o algún texto que debe escribirse en un archivo? Si especifica texto, ¿cuál es el nombre del archivo en el que le gustaría escribir este contenido?
jahroy
$ var contiene el texto que quiero copiar y el archivo en el que se debe escribir está definido por el usuario, de ahí la razón por la que estoy usando una variable en primer lugar.
user1546083
1
Quizás $destdirdebería nombrarse $destfilepara que no sea engañoso ... El nombre $destdirsugiere que especifica un directorio en lugar de un archivo. Esto haría que toda su pregunta fuera sencilla y fácil de entender.
jahroy

Respuestas:

145

Usa el echocomando:

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

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

Las ifpruebas que $destdirrepresenta un archivo.

El >anexa el texto después de truncar el archivo. Si solo desea agregar el texto $varal contenido existente del archivo, utilice >>en su lugar:

echo "$var" >> "$destdir"

El cpcomando se usa para copiar archivos (a archivos), no para escribir texto en un archivo.

pb2q
fuente
4
Necesita más comillas: en este momento, cualquier ejecución de espacios en blanco dentro del valor de la variable se convertirá en un solo espacio, las expresiones globales se expandirán, etc.
Charles Duffy
2
Otra cosa - se necesita un espacio entre la cotización de cierre y la ]de "$destdir"].
Charles Duffy
3
echotambién agrega una nueva línea final a su variable.
Ben Dilts
6
Esto falla si $vares -e text to append, y en realidad no escribe el-e
Eric
1
Debido a echo $varque depende del shell para expandir su variable, no funciona muy bien con cosas como espacios en blanco y caracteres especiales. Puede usar perl -e 'print($ENV{var})'en su lugar, y generará precisamente el valor de la variable.
Blake Mitchell
38

echotiene el problema de que si varcontiene algo como -e, se interpretará como una bandera. Otra opción es printf, pero printf "$var" > "$destdir"expandirá los caracteres de escape en la variable, por lo que si la variable contiene barras invertidas, el contenido del archivo no coincidirá. Sin embargo, debido a que printfsolo interpreta las barras invertidas como escapes en la cadena de formato, puede usar el %sespecificador de formato para almacenar el contenido exacto de la variable en el archivo de destino:

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

Trebawa
fuente
1
printf también es bueno si tiene nuevas líneas en la cadena variable, como de una comilla triple o heredoc. echo no maneja bien las nuevas líneas.
Beeflobill
@beeflobill puede explicar cómo "echo no maneja bien las nuevas líneas". Lo único que he visto es que echo agrega una nueva línea. Lo que hace echo "$var" > destfilemal.
SensorSmith
@SensorSmith En mis experimentos, veo que cuando la cadena tiene "\ n" ese eco imprimirá un carácter de nueva línea. Pero, si la cadena tiene un carácter de nueva línea real, ese eco no lo imprimirá. No sé por qué.
Beeflobill
1
Básicamente un problema de portabilidad (y confiabilidad). unix.stackexchange.com/a/65819… o para los mortales entre nosotros: printfes mejor, sigue adelante.
user3342816
29

Ninguna de las respuestas anteriores funciona si su variable:

  • comienza con -e
  • comienza con -n
  • comienza con -E
  • contiene un \seguido de unn
  • no se debe agregar una nueva línea adicional después

por lo que no se puede confiar en ellos para contenidos de cadenas arbitrarios.

En bash, puede usar "here strings" como:

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

Como se indica en el comentario a continuación, la respuesta de @ Trebawa (¡formulada en la misma habitación que la mía!) El uso printfes un mejor enfoque.

Eric
fuente
5
Por lo que puedo decir, cat siempre insertará una nueva línea al final del archivo, independientemente de que no haya una nueva línea al final de la variable (aunque podría decirse que esto es algo bueno en la mayoría de los casos). La respuesta usando printf parece evitar insertar una nueva línea al final.
Ash
@Ash otra ventaja de printfover cates que el primero es un shell incorporado que siempre se ejecutará más rápido que un binario externo.
Géza Török
7

Si te entendí bien, querrás copiar $varen un archivo (si es una cadena).

echo $var > $destdir
qwertz
fuente
Así es como se hace. El uso del cpcomando hará que el shell interprete el primer argumento como el nombre de un archivo o directorio.
jahroy
5
Si no incluye $varentre comillas, el contenido del archivo no es 100% igual al contenido de $ var en algunos casos. Por ejemplo, cuando "repite" vars que contienen claves RSA, obtiene una clave no válida en el archivo.
srigi
6
Falla si $varcontiene espacios o-e
Eric
1

Cuando dice "copiar el contenido de una variable", ¿esa variable contiene un nombre de archivo o contiene el nombre de un archivo?

Supongo por su pregunta que $varcontiene el contenido que desea copiar en el archivo:

$ echo "$var" > "$destdir"

Esto hará eco del valor de $ var en un archivo llamado $ destdir. Tenga en cuenta las comillas. Es muy importante tener "$ var" entre comillas. También para "$ destdir" si hay un espacio en el nombre. Para adjuntarlo:

$ echo "$var" >> "$destdir"
David W.
fuente
3
Falla si varcontiene-e
Eric
1
Pasar un guión doble como primer argumento para echo terminar su lista de opciones, resuelve así el problema planteado por @Eric:echo -- "$var" >> "$destfile"
Géza Török
1

Todo lo anterior funciona, pero también tiene que solucionar un problema (escapes y caracteres especiales) que no es necesario que ocurra en primer lugar: caracteres especiales cuando el shell expande la variable. Simplemente no hagas eso (expansión variable) en primer lugar. Utilice la variable directamente, sin expansión.

Además, si su variable contiene un secreto y desea copiar ese secreto en un archivo, es posible que desee no tener expansión en la línea de comandos, ya que el rastreo / eco de comando de los comandos de shell podría revelar el secreto. Significa que todas las respuestas que se usan $varen la línea de comando pueden tener un riesgo potencial de seguridad al exponer el contenido variable al rastreo y registro del shell.

Utilizar este:

printenv var >file

Eso significa, en el caso de la pregunta OP:

printenv var >"$destfile"
Christian Hujer
fuente