web-dev-qa-db-fra.com

Comment chatter << EOF >> un fichier contenant du code?

Je veux imprimer le code dans un fichier en utilisant cat <<EOF >>:

cat <<EOF >> brightup.sh
!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
   curr=$((curr+406));
   echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi
EOF

mais quand je vérifie la sortie du fichier, j'obtiens ceci:

!/bin/bash
curr=1634
if [  -lt 4477 ]; then
   curr=406;
   echo   > /sys/class/backlight/intel_backlight/brightness;
fi

J'ai essayé de mettre des guillemets simples, mais la sortie comporte également les guillemets simples. Comment puis-je éviter ce problème?

74
UberNate

Vous n'avez besoin que d'un changement minimal. citez le délimiteur here-document après <<.

cat <<'EOF' >> brightup.sh

ou l'équivalent de backslash-escape:

cat <<\EOF >>brightup.sh

Sans citer, le document ici subira une substitution de variable, les backticks seront évalués, etc., comme vous l'avez découvert.

Si vous devez développer certaines valeurs, mais pas toutes, vous devez échapper individuellement à celles que vous souhaitez empêcher.

cat <<EOF >>brightup.sh
#!/bin/sh
# Created on $(date # : <<-- this will be evaluated before cat;)
echo "\$HOME will not be evaluated because it is backslash-escaped"
EOF

produira

#!/bin/sh
# Created on Fri Feb 16 11:00:18 UTC 2018
echo "$HOME will not be evaluated because it is backslash-escaped"

Comme suggéré par @ fedorqui , voici la section pertinente de man bash:

Voici des documents

Ce type de redirection demande au shell de lire les entrées de la source actuelle jusqu’à ce qu’une ligne contenant uniquement un délimiteur (sans blancs à la fin) soit visible. Toutes les lignes lues jusqu'à ce point sont ensuite utilisées comme entrée standard pour une commande.

Le format de here-documents est:

      <<[-]Word
              here-document
      delimiter

Aucun développement de paramètre, substitution de commande, développement arithmétique ou développement de chemin d'accès n'est effectué sur Word. Si des caractères sont cités dans Word, le délimiteur est le résultat de la suppression des guillemets dans Word et les lignes du document here ne sont pas développées. Si Word n'est pas entre guillemets, toutes les lignes du document here sont soumises à l'expansion des paramètres, à la substitution de commandes et à l'expansion arithmétique . Dans ce dernier cas, la séquence de caractères\est ignorée et doit être utilisée pour citer les caractères \, $ et `.

117
tripleee

Ou bien, en utilisant vos marqueurs EOF, vous devez citer le marqueur initial pour que l'extension ne soit pas effectuée:

#-----v---v------
cat <<'EOF' >> brightup.sh
#!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
   curr=$((curr+406));
   echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi
EOF

IHTH

18
shellter

Cela devrait fonctionner, je viens de le tester et cela a fonctionné comme prévu: aucune expansion, substitution, ou quoi que vous ayez eu.

cat <<< '
#!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
  curr=$((curr+406));
  echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi' > file # use overwrite mode so that you don't keep on appending the same script to that file over and over again, unless that's what you want. 

Utiliser ce qui suit fonctionne aussi.

cat <<< ' > file
 ... code ...'

En outre, il convient de noter que lorsqu’on utilise heredocs, tel que << EOF, la substitution et l’extension de variable, etc., ont lieu. Donc, faire quelque chose comme ça:

cat << EOF > file
cd "$HOME"
echo "$PWD" # echo the current path
EOF

entraînera toujours le développement des variables $HOME et $PWD. Donc, si votre répertoire personnel est /home/foobar et que le chemin actuel est /home/foobar/bin, file ressemblera à ceci:

cd "/home/foobar"
echo "/home/foobar/bin"

au lieu de l'attendu:

cd "$HOME"
echo "$PWD"
9
Alexej Magura