Les bizarreries de bash

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Je ne comprends pas très bien toutes les subtilités du langage bash.
En apprendre davantage m’aiderait à produire du meilleur code.

J’ai déjà consulté le tutoriel d’openclassroom et celui proposé par mon école, mais ils sont tous les deux incomplets ou trop superficiels. De plus, le bash est un langage dont la syntaxe est très stricte (à l’espace près souvent).

Bref, en particulier je voulais savoir quelle est la différence entre ces différentes notations et pourquoi la plus longue est la plus utilisée même pour des variables courtes :

# Notation simple, efficace mais peu utilisée, pourquoi ?
if [ $# -ne 2 ]; then

# Autres écritures de la première ligne :
if [ "$#" -ne "2" ]; then
if ["${#}" -ne "2" ]; then # c'est le plus utilisé

Les doubles-guillemets autour d’une variable servent à quoi ?

Salut,

C’est une façon d’être plus explicite sur ce qui se passe par défaut. Bash manipule des chaînes de caractères.

Le programme suivant, contrairement à ce à quoi on pourrait s’attendre, affiche "OK"

#!/bin/bash

a=23

if [[ $a < 3 ]]; then
    echo OK
fi

Si on est plus explicite et que l’on écrit [[ "${a}" < "3" ]], on comprend que le test est fait sur des chaînes de caractères et on comprend mieux pourquoi le programme affiche "OK". En gros, on diminue les effets de surprise liés à la conception bancale de bash.

+0 -0

Salut,

Les doubles-guillemets autour d’une variable servent à quoi ?

Green

Dans le cas de la variable $#, elles sont inutiles. Je suis d’ailleurs surpris que tu précises qu’il s’agit de la notation la plus utilisée, je suis de mon côté d’avis que c’est justement la première qui est idiomatique, les autres montrent surtout une absence de compréhension de mon point de vue.

En bash ou shell POSIX de manière plus générale, les guillements doubles servent à éviter l’interprétation des caractère spéciaux (comme *, [pattern] ou ?) à l’exception de \, $ et `. Elles permettent également d’éviter l’interprétation des espaces (au sens large : espace, tabulation, retour à la ligne, etc.).

Dans ton exemple, la variable $# est toujours remplacée par nombre, il n’y a donc pas lieu d’appliquer de guillemets doubles. Idem pour une constante littérale entière.

+0 -0

La doc officielle de GNU bash. Mais en vrai, je conseille plutôt aux gens de se tenir à l’écart de bash. Avoir des bases pour quand on tombe sur un script déjà écrit (ou un contexte où on n’a pas le choix) et pouvoir le modifier, c’est bien. Par contre, passer du temps pour comprendre bash à fond alors que c’est un outil dépassé (pour exemple, Python fait bien mieux le job à part de très rares cas), ça me semble pas un bon investissement.

+3 -1

Oui. En tant que langage de script, bash est extrêmement mal foutu. Pas la moindre once de typage, une syntaxe obscure, pas de structures de données avancées. Bref, c’est un langage tout pourri comparé à n’importe quel langage de programmation un peu sérieux. À moins que ce soit le seul langage adapté au scripting présent sur la machine (et c’est extrêmement rare de pas avoir au moins Python qui traîne), écrire un script dans ce langage, c’est se tirer une balle dans le pied. Le seul cas d’usage un minimum pertinent, c’est si on souhaite effectuer un traitement simple en le reléguant à d’autres commandes comme sed, grep, etc, sans avoir une logique métier complexe à avoir à coder en bash (et dans ce cas, maîtriser les arcanes de bash n’est pas nécessaire)

+3 -0

Je plusseoie fortement @adri1

À l’école d’ingé (il y a une bonne douzaine d’années de ça), j’ai eu la preuve ultime que bash est à la fois puissant et complètement pourri pour faire quoi que ce soit : j’ai comme projet « faire un jeu de dames jouable par deux utilisateurs connectés au même serveur (en CLI) ».

C’est possible (sans gérer les déplacements des dames). Mais c’est tellement compliqué pour rien que c’en est impressionnant.

Oui. En tant que langage de script, bash est extrêmement mal foutu. Pas la moindre once de typage, une syntaxe obscure, pas de structures de données avancées. Bref, c’est un langage tout pourri comparé à n’importe quel langage de programmation un peu sérieux.

adri1

De ce côté, on est bien d’accord.

À moins que ce soit le seul langage adapté au scripting présent sur la machine (et c’est extrêmement rare de pas avoir au moins Python qui traîne), écrire un script dans ce langage, c’est se tirer une balle dans le pied. Le seul cas d’usage un minimum pertinent, c’est si on souhaite effectuer un traitement simple en le reléguant à d’autres commandes comme sed, grep, etc, sans avoir une logique métier complexe à avoir à coder en bash (et dans ce cas, maîtriser les arcanes de bash n’est pas nécessaire)

adri1

Là par contre, je ne te rejoins pas : bash ou tout shell POSIX tire clairement son épingle du jeu au niveau de l’administration système, même pour des scripts complexes (bon, c’est du ksh, mais bref). La raison en est simple : l’administration système repose sur une chiée de commandes (entre le lancement d’un service, la vérification du statut d’un service, lister les ports en écoute, la gestion des privilèges, l’installation ou la suppression de paquets et j’en passe) et c’est justement un langage permettant de lancer différentes commandes et gérer leurs sorties qui est nécessaire.

C’est de mon point de vue écrire cela avec un langage généraliste qui consisterait justement à se tirer une balle dans le pied. Si tu prends le cas du C, ce serait juste immonde : une suite de fork(), exec() et des entrées et sorties dans tous les sens. Évidemment, cela serait moins pénible en Python, mais cela resterait moins efficace que du shell POSIX à mon humble avis.

+0 -0

Ton script a une logique métier assez bateau (et on notera à quel point il est tout de même déjà violemment cryptique).

C’est de mon point de vue écrire cela avec un langage généraliste qui consisterait justement à se tirer une balle dans le pied. Si tu prends le cas du C, ce serait juste immonde

Si je réponds à ça, ça va partir en grosse catastrophe comme ils disent à Massilia.

Évidemment, cela serait moins pénible en Python, mais cela resterait moins efficace que du shell POSIX à mon humble avis.

J’en doute fort. Les modules comme shutil et subprocess rendent assez agréable l’écriture (et la lecture !) de ce genre de scripts. On pourrait bien sûr arguer que c’est une question d’habitude. La learning curve me semble moins pentue avec Python cela dit.

+1 -0

Je suis plutôt d’accord, en tant que noob ayant déjà des bases en Python, que bash est inutilement compliqué. Bon, on doit l’apprendre à l’école et se taire, pas le choix.
Mais je suppose qu’historiquement, ce langage devait avoir un intérêt à l’époque, peut-être que Python n’existait pas à l’époque. D’où le fait qu’il soit désuet aujourd’hui. Mais je m’avance peut-être trop.

Ton script a une logique métier assez bateau (et on notera à quel point il est tout de même déjà violemment cryptique).

adri1

Ok, je pense qu’on s’est juste mal compris sur le terme « complexe », mais bref. Le script n’est pas spécifiquement si trivial que cela, entre la gestion des privilèges, le téléchargements des patchs, les vérifications cryptographiques et la gestion des signaux.

J’en doute fort. Les modules comme shutil et subprocess rendent assez agréable l’écriture (et la lecture !) de ce genre de scripts.

adri1

De ce côté, je dis chiche. :D

Si je réponds à ça, ça va partir en grosse catastrophe comme ils disent à Massilia.

adri1

Bof, tu sais tant que cela part pas en salve d’insultes, tu peux avoir l’avis que tu veux. ^^

Mais je suppose qu’historiquement, ce langage devait avoir un intérêt à l’époque, peut-être que Python n’existait pas à l’époque. D’où le fait qu’il soit désuet aujourd’hui. Mais je m’avance peut-être trop.

Green

« Désuet », vraiment ? Je te rappel que c’est le langage qui interprète les commandes que tu entres dans ton terminal. ;)

+1 -0

« Désuet », vraiment ? Je te rappel que c’est le langage qui interprète les commandes que tu entres dans ton terminal. ;)

Hum… tu marques un point. J’entendais par désuet l’apprentissage des scripts bash aussi poussés qu’on voit à l’école, après mes études c’est informatique :-°

J’entendais par désuet l’apprentissage des scripts bash aussi poussés qu’on voit à l’école, après mes études c’est informatique :-°

Green

Je ne sais jusqu’où vous poussez le vice, mais si c’est au point de faire un jeu de dames ou un Puissance 4 en bash alors oui, c’est du masochisme. ^^"

+0 -0

Je ne sais jusqu’où vous poussez le vice, mais si c’est au point de faire un jeu de dames ou un Puissance 4 en bash alors oui, c’est du masochisme. ^^"

Taurre

Honnêtement, le script du jeu de dames n’était pas moins lisible que t’exemple de ton message ci-dessus.

Et c’est probablement là le principal défaut de bash : même un lot de commandes à lancer toujours dans le même ordre peut devenir assez peu lisible. Et la moindre variable ou structure de contrôle a une syntaxe si foireuse que leur présence rends immédiatement le script disponible en écriture seule. Et je ne parle pas des structures complètement cryptiques que ça utilise, par exemple l’une des premières lignes de l’exemple :

echo "${0##*/}: ${1}" 1>&2 && return ${2:-1}

Honnêtement, le script du jeu de dames n’était pas moins lisible que t’exemple de ton message ci-dessus.

SpaceFox

Ah ? o_O

Et c’est probablement là le principal défaut de bash : même un lot de commandes à lancer toujours dans le même ordre peut devenir assez peu lisible. Et la moindre variable ou structure de contrôle a une syntaxe si foireuse que leur présence rends immédiatement le script disponible en écriture seule.

SpaceFox

Cela me paraît quand même un peu excessif. Oui, la syntaxe est pas top parce que fort dense, mais de là à ce que cela soit « en écriture seule » c’est allez un peu trop loin, je pense. D’autant qu’il y aussi le facteur humain qui rentre en ligne de compte : un script lisible cela ne dépend pas que de la syntaxe du langage.

Par exemple, la fonction sp_error() pourrait être réécrite comme suit.

# $1: error message to print
# $2: return code of the program
sp_error()
{
    _progname="${0##*/}"
    _message="$1"
    _code="$2"

    echo >&2 "${_progname}: ${_message}"

    if [ $# -le 1 ]
    then
        return 1
    else
        return ${_code}
    fi
}

Je sais qu’on est d’accord sur le fond : la syntaxe est pas folichone, je trouve juste qu’il ne faut pas diaboliser l’outil ou le considérer comme « obsolète » ou « désuet ».

Et je ne parle pas des structures complètement cryptiques que ça utilise, par exemple l’une des premières lignes de l’exemple :

echo "${0##*/}: ${1}" 1>&2 && return ${2:-1}

SpaceFox

Bon, là je peux pas juger objectivement parce que je connais la syntaxe. ^^"

+0 -0

Cela me paraît quand même un peu excessif. Oui, la syntaxe est pas top parce que fort dense, mais de là à ce que cela soit « en écriture seule » c’est allez un peu trop loin, je pense. D’autant qu’il y aussi le facteur humain qui rentre en ligne de compte : un script lisible cela ne dépend pas que de la syntaxe du langage.

Taurre

Non, je parle d’expérience. Reprendre des scripts bash que tu n’as pas développé toi-même, c’est tomber dans l’un de ces deux cas :

  1. La personne a massivement documenté son script et n’a pas utilisé 90 % des possibilités de bash pour le garder lisible (notamment les chainages avec && ou ||), et là ça va.
  2. La personne a développé ça sur un coin de table, et/ou a utilisé plein de fonctionnalités obscures du langage, et là autant redévelopper le script, ça va plus vite.

Le langage est problématique à la fois par sa syntaxe (à la fois trop compacte, pas assez sur certains points comme les variables, et sensible à des questions de formatage), par son éloignement de tout autre langage de programmation et par son utilisation-type (c’est rare que développer en bash soit autre chose qu’une petite partie de ton boulot). Tout ça contribue au fait que relire un code bash développé par quelqu’un d’autre est très compliqué, surtout quand tu ne fais pas ça à plein temps et que donc toutes les subtilités de bash t’échappent (au moins le temps de s’en rappeler).

D’ailleurs tu en donnes un très bon exemple toi-même :

Bon, là je peux pas juger objectivement parce que je connais la syntaxe. ^^"

Taurre

Dans beaucoup de langages, tu peux souvent deviner ce que fait le code, soit parce que c’est « naturellement clair », soit parce que ça ressemble à un autre langage déjà connu. Bash utilise beaucoup trop de structures qu’il est le seul à utiliser.

Euh, en tant que personne qui connaît peu le bash (j’ai des notions suffisantes pour plein de truc mais c’est tout), je me demandais ce que voulais dire:

${0##*/}

Je suppose que c’est un traitement spécifique apporté à $0, mais je ne sais pas lequel… D’ailleurs je ne savais pas que les redirections de sorties pouvaient ne pas se faire à la fin de la commande.

Euh, en tant que personne qui connaît peu le bash (j’ai des notions suffisantes pour plein de truc mais c’est tout), je me demandais ce que voulais dire:

${0##*/}

Je suppose que c’est un traitement spécifique apporté à $0, mais je ne sais pas lequel… D’ailleurs je ne savais pas que les redirections de sorties pouvaient ne pas se faire à la fin de la commande.

charlie02

Ah en fait c’est tout simple. Le ## indique qu’on souhaite supprimer en début de chaine la première occurrence de [insérer ici n’importe quoi]/.

Par exemple, le script ci-dessous….

#!/bin/bash

echo $0
echo ${0##*/}

renvoie :

./script.sh
script.sh

Ah en fait c’est tout simple. Le ## indique qu’on souhaite supprimer en début de chaine la première occurrence de [insérer ici n’importe quoi]/.

Green

Ça, c’est la définition de #. ;)
Si tu utilises ## cela signifie « la plus longue occurrence ».

Autrement dit, si la chaîne chaine contient /on/a/parcouru/le/chemin :

  • ${chaine#*/} donnera on/a/parcouru/le/chemin ;
  • ${chaine##*/} donnera chemin.

Et j’avais aussi croisé le même genre de commande mais en remplaçant ## par %. c’est la même chose appliqué à toutes les occurrences?

charlie02

Les symboles % et %% sont identiques aux autres si ce n’est qu’ils travaillent depuis la fin de la chaîne.

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte