Comment diviser une longue chaîne en plusieurs lignes à l'invite de lecture -p dans le code source?


18

J'écris un script d'installation qui sera exécuté en tant que /bin/sh.

Une ligne demande un fichier:

read -p "goat can try change directory if cd fails to do so. Would you like to add this feature? [Y|n] " REPLY

Je voudrais diviser cette longue ligne en plusieurs lignes afin qu'aucune d'entre elles ne dépasse 80 caractères. Je parle des lignes dans le code source du script; pas sur les lignes qui doivent être réellement imprimées à l'écran lors de l'exécution du script!

Ce que j'ai essayé:

  • Première approche:

    read -p "goat can try change directory if cd fails to do so. " \
        "Would you like to add this feature? [Y|n] " REPLY

    Cela ne fonctionne pas car il n'imprime pas Would you like to add this feature? [Y|n].

  • Deuxième approche:

    echo "goat can try change directory if cd fails to do so. " \
        "Would you like to add this feature? [Y|n] "
    read REPLY

    Ça ne marche pas aussi bien. Il imprime une nouvelle ligne après l'invite. L'ajout d'une -noption echon'aide pas: elle imprime simplement:

    -n goat can try change directory if cd fails to do so. Would you like to add this feature? [Y|n]
    # empty line here
  • Ma solution de contournement actuelle est

    printf '%s %s ' \
        "goat can try change directory if cd fails to do so." \
        "Would you like to add this feature? [Y|n] "
    read REPLY

et je me demande s'il y a une meilleure façon.

N'oubliez pas que je recherche une /bin/shsolution compatible.


1
Je vous suggère 1. d'utiliser un terminal et / ou une fenêtre d'éditeur plus large (par exemple, j'utilise un terminal de 192 colonnes par 51 lignes sur mon moniteur 1440p - idéal pour suivre les fichiers journaux et éditer le code source dans vim) et 2. apprendre à accepter le le fait que parfois les lignes de code source dépassent 80 caractères - c'est inévitable. Si j'utilisais une police plus petite, je pourrais avoir un terminal encore plus large mais ma configuration actuelle est un bon compromis entre largeur et lisibilité.
cas

Réponses:


16

Tout d'abord, découplons la lecture de la ligne de texte en utilisant une variable:

text="line-1 line-2"             ### Just an example.
read -p "$text" REPLY

De cette façon, le problème devient: Comment affecter deux lignes à une variable.

Bien sûr, une première tentative pour ce faire est:

a="line-1 \
line-2"

Écrit comme ça, le var aobtient réellement la valeur line-1 line-2.

Mais vous n'aimez pas le manque d'indentation que cela crée, eh bien, alors nous pouvons essayer de lire les lignes dans le var à partir d'un document ici (sachez que les lignes en retrait à l'intérieur du document ici ont besoin d'un onglet, pas d'espaces, pour fonctionner correctement):

    a="$(cat <<-_set_a_variable_
        line-1
        line-2
        _set_a_variable_
    )"
echo "test1 <$a>"

Mais cela échouerait car en réalité deux lignes sont écrites sur $a . Une solution de contournement pour obtenir une seule ligne peut être:

    a="$( echo $(cat <<-_set_a_variable_
        line 1
        line 2
        _set_a_variable_
        ) )"
echo "test2 <$a>"

C'est proche, mais cela crée d'autres problèmes supplémentaires.

Solution correcte.

Toutes les tentatives ci-dessus ne feront que rendre ce problème plus complexe qu'il ne doit l'être.

Une approche très basique et simple est:

a="line-1"
a="$a line-2"
read -p "$a" REPLY

Le code de votre exemple spécifique est (pour tout shell dont les readsupports -p):

#!/bin/dash
    a="goat can try change directory if cd fails to do so."
    a="$a Would you like to add this feature? [Y|n] "
# absolute freedom to indent as you see fit.
        read -p "$a" REPLY

Pour tous les autres coques, utilisez:

#!/bin/dash
    a="goat can try change directory if cd fails to do so."
    a="$a Would you like to add this feature? [Y|n] "
# absolute freedom to indent as you see fit.
        printf '%s' "$a"; read REPLY

@BinaryZebra je sais. Je viens de corriger le "pour tout shell" car tous les shells n'ont pas lu et pas tous ceux qui ont -p.
terdon

@terdon Nous sommes tous les deux d'accord C'est la raison des remerciements :-). Merci encore.

1

La barre oblique inversée à la fin des lignes permet la poursuite de la commande sur plusieurs lignes, et non des sauts de ligne réels dans la sortie.

Ainsi, votre première approche, par exemple, devient la commande

read -p "goat can try change directory if cd fails to do so. " "Would you like to add this feature? [Y|n] " REPLY

Je ne sais pas pourquoi vous voulez lire pour produire plusieurs lignes, mais j'utiliserais simplement read la ligne d'invite et echola ou les lignes précédentes.

Pour rendre le code plus lisible sur plusieurs lignes, ne fermez pas / n'ouvrez pas vos guillemets entre les lignes.

Essaye ça:

read -p "goat can try change directory if cd fails to do so. \
Would you like to add this feature? [Y|n] " REPLY

Je ne veux pas qu'il imprime deux lignes! Je veux juste que le code tienne en 80 caractères par ligne dans le code source du script ! Merci pour la réponse cependant :)
Mateusz Piotrowski

Je n'aime pas l'approche que vous avez suggérée car il n'y a pas de retrait. Si my readest indenté dans une fonction, votre approche semble gâcher la lisibilité.
Mateusz Piotrowski

1

Je trouve l'approche de @ BinaryZebra utilisant une variable plus propre, mais vous pouvez également le faire comme vous le tentiez. Il vous suffit de conserver les sauts de ligne à l'intérieur des guillemets:

read -p "goat can try change directory if cd fails to do so. \
Would you like to add this feature? [Y|n] " REPLY

Pensez-vous que l'ajout de nouvelles lignes après chaque ligne augmenterait la lisibilité? Parce que je ne cherchais pas le moyen de l'insérer \ndans mon invite. Je voulais juste diviser le code en plusieurs lignes afin que chaque ligne contienne au plus 80 caractères.
Mateusz Piotrowski

1
@MateuszPiotrowski oh, cela a beaucoup plus de sens. Alors ma réponse n'est pas très utile. Veuillez modifier votre question et préciser que vous souhaitez diviser le code et non la sortie. Je suis sur mobile maintenant mais je vais voir si je peux trouver quelque chose demain.
terdon

1
@MateuszPiotrowski fait, j'ai ajouté une version de travail de ce que vous essayiez à l'origine.
terdon

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.