web-dev-qa-db-fra.com

Faire écho à une commande echo avec une variable dans bash

Ok, voici celui avec lequel je me bats en ce moment. Faire écho à une commande d'écho avec une variable.

echo "creating new script file."
echo "#!/bin/bash" > $servsfile
echo "read -p "Please enter a service: " ser " >> $servfile
echo "servicetest=`getsebool -a | grep ${ser}` " >> $servfile
echo "if [ $servicetest > /dev/null ];then " >> $servfile
echo "echo "we are now going to work with ${ser}" " >> $servfile
echo "else" >> $servfile
echo "exit 1" >> $servfile
echo "fi" >> $servfile

Mon objectif est de créer un script à l'aide des commandes echo puis de l'exécuter plus tard. J'ai juste besoin de comprendre comment faire écho aux commandes echo/read tout en maintenant mes variables.

edit: les variables doivent transférer ce qu'elles contiennent dans le nouveau fichier.

20
David

Le problème immédiat est que vous avez à citer: en utilisant des guillemets doubles, vos références de variables sont instantanément développé , ce qui n'est probablement pas ce que vous voulez.

Utilisez single guillemets à la place - les chaînes à l'intérieur des guillemets simples ne sont pas développées ou interprétées de quelque façon par le shell.

(Si vous voulez sélectif expansion à l'intérieur d'une chaîne - c'est-à-dire, développez certaines références de variables, mais pas d'autres - utilisez des guillemets doubles, mais préfixez le $ Des références que vous faites pas souhaite être développé avec \; par exemple, \$var).

Cependant, il vaut mieux utiliser un seul ici-doc [ument], ce qui vous permet de créer plusieurs lignes stdin entrée sur place, entre crochets par deux instances d'un auto-choisi délimiteur, celui d'ouverture préfixé par <<, Et la dernière sur une ligne seule - à partir de la toute première colonne; recherchez Here Documents dans man bash ou sur http://www.gnu.org/software/bash/manual/html_node/Redirections.html .

Si vous citation le here-doc délimiteur (EOF dans le code ci-dessous), références variables sont également pas développés . Comme le souligne @chepner, vous êtes libre de choisir la méthode de citation dans ce cas: mettez le délimiteur entre guillemets simples ou guillemets doubles, ou même simplement échapper arbitrairement un caractère dans le délimiteur avec \:

echo "creating new script file."

cat <<'EOF'  > "$servfile"
#!/bin/bash
read -p "Please enter a service: " ser
servicetest=`getsebool -a | grep ${ser}` 
if [ $servicetest > /dev/null ]; then 
  echo "we are now going to work with ${ser}"
else
  exit 1
fi
EOF

Comme le note @BruceK, vous pouvez préfixer votre délimiteur ici-doc avec - (appliqué à cet exemple: <<-"EOF") Pour avoir onglets supprimés, permettant une indentation qui rend le contenu réel du document ici plus facile à discerner. Notez, cependant, que cela ne fonctionne qu'avec les caractères tab réels, pas les espaces en tête.

En utilisant cette technique combinée avec les réflexions sur le contenu du script ci-dessous, nous obtenons (encore une fois, notez que tab caractères réels. doit être utilisé pour diriger chaque ligne de contenu ici-doc pour qu'ils soient supprimés):

cat <<-'EOF' > "$servfile"
    #!/bin/bash
    read -p "Please enter a service name: " ser
    if [[ -n $(getsebool -a | grep "${ser}") ]]; then 
      echo "We are now going to work with ${ser}."
    else
      exit 1
    fi
EOF

Enfin, notez que dans bash even les chaînes normales entre guillemets simples ou doubles peuvent s'étendre sur plusieurs lignes, mais vous n'obtiendrez pas les avantages de la suppression de tabulation ou du blocage de ligne portée, comme tout à l'intérieur des guillemets devient une partie de la chaîne.

Ainsi, notez comment dans le suivant #!/bin/bash Doit suivre l'ouverture ' immédiatement pour devenir la première ligne de sortie:

echo '#!/bin/bash
read -p "Please enter a service: " ser
servicetest=$(getsebool -a | grep "${ser}")
if [[ -n $servicetest ]]; then 
  echo "we are now going to work with ${ser}"
else
  exit 1
fi' > "$servfile"

Réflexions sur le contenu de votre script:

  • La syntaxe $(...) est préférée à `...` Pour la substitution de commandes de nos jours.
  • Vous devez entre guillemets ${ser} Dans la commande grep, car la commande se cassera probablement si la valeur contient des espaces incorporés (sinon, assurez-vous que la valeur lue ne contient pas d'espaces ou d'autres métacaractères Shell) .
  • Utilisez [[ -n $servicetest ]] Pour tester si $servicetest Est vide (ou effectuez la substitution de commande directement à l'intérieur du conditionnel) - [[ ... ]] - la forme préférée dans bash - vous protège de casser le conditionnel si le $servicetest se trouve avoir des espaces intégrés; il n'est JAMAIS nécessaire de supprimer la sortie stdout dans un conditionnel (que ce soit [ ... ] ou [[ ... ]], car aucune sortie stdout n'est transmise; ainsi, le > /dev/null est redondant (cela dit, avec une substitution de commande à l'intérieur d'un conditionnel, stderr sortie IS passé).
22
mklement0

Il vous suffit d'utiliser des guillemets simples:

$ echo "$TEST"
test
$ echo '$TEST'
$TEST

À l'intérieur des guillemets simples, les caractères spéciaux ne sont plus spéciaux, ce ne sont que des caractères normaux.

13
Mihai
echo "echo "we are now going to work with ${ser}" " >> $servfile

Échapper tout "entre guillemets avec \. Faites cela avec des variables comme\$ servicetest aussi:

echo "echo \"we are now going to work with \${ser}\" " >> $servfile    
echo "read -p \"Please enter a service: \" ser " >> $servfile
echo "if [ \$servicetest > /dev/null ];then " >> $servfile
8
GoinOff