Où sont zsh et mksh incompatibles avec bash?

11

Dans quelle mesure d'autres shells compatibles POSIX peuvent-ils fonctionner comme des remplacements raisonnables pour bash? Ils n'ont pas besoin d'être de véritables remplacements "drop-in", mais suffisamment proches pour fonctionner avec la plupart des scripts et prendre en charge le reste avec quelques modifications.

  1. Je veux que les scripts bash explicites - initscripts, scripts client DHCP, etc. - fonctionnent avec un minimum de modifications

  2. Je veux que ma propre collection de scripts shell plus spécialisés n'ait pas besoin de trop de modifications

  3. Je veux avoir des fonctionnalités comme la manipulation de chaînes et la correspondance de motifs regex intégrée

Les seuls prétendants sérieux que je connaisse sont zsh et mksh. Donc, pour ceux d'entre vous ici qui sont bons avec l'un ou les deux:

  1. Quelles sont les fonctionnalités de bash que zsh et mksh respectivement n'ont pas?

  2. Quelles fonctionnalités les shells partagent avec bash, mais utilisent une syntaxe incompatible pour?

DanL4096
la source
3
Comparaison des shells de commande: ( en.wikipedia.org/wiki/Comparison_of_command_shells ) Guide avancé des scripts Bash: ( tldp.org/LDP/abs/html ) Manuel ZSH: ( zsh.sourceforge.net/Guide/zshguide.html ) MirBSD Manuel Shell: ( mirbsd.org/htman/i386/man1/mksh.htm ). Je suis désolé, mais cette question est trop complexe. Peut-être devriez-vous demander comment patcher bash pour corriger la vulnérabilité dans votre distribution spécifique de Linux?
Tyler Maginnis du
3
Il n'y a pas de shell qui puisse fonctionner en remplacement de bash, mksh et zsh peuvent fonctionner comme /bin/shavec différents niveaux de correction, mais pas bash.
llua
1
Le truc du shellshock semble n'avoir rien à voir avec la question centrale et ne fait que distraire les gens, alors je l'ai supprimé
Michael Mrozek
3
Toute la question est trop large. Vous devriez peut-être le supprimer.
Tyler Maginnis
1
La seule préoccupation que j'ai vraiment, c'est que BASH est bien entretenu par la Free Software Foundation (FSF). Mes contacts là-bas me disent que la révélation de la "faille fondamentale" au sein de BASH ne conduira qu'à une mise en œuvre plus forte et plus sûre. Il y a tellement de coques alternatives que même en commençant à en recommander une pour vos besoins, j'aurais besoin d'une solide compréhension de votre cas d'utilisation. Du côté O / S ... Tant de choses sont liées à Bash que vous pourriez finir par réécrire l'intégralité de vos appels O / S vers BASH. La meilleure solution que je puisse voir est de choisir une distribution avec un alt-shell maintenu.
Tyler Maginnis

Réponses:

19

Je m'en tiendrai aux fonctionnalités de script. De riches fonctionnalités interactives (édition en ligne de commande, complétion, invites, etc.) ont tendance à être très différentes, obtenant des effets similaires de manière totalement incompatible. Quelles fonctionnalités sont dans zsh et manquent dans bash, ou vice versa? donne quelques conseils sur l'utilisation interactive.

La chose la plus proche de bash serait ATT ksh93 ou mksh (le shell Korn et un clone). Zsh possède également un sous-ensemble de fonctionnalités, mais vous devez l'exécuter en mode d'émulation ksh, pas en mode natif zsh.

Je ne listerai pas les fonctionnalités POSIX (qui sont disponibles dans n'importe quel shshell moderne ), ni les fonctionnalités relativement obscures, ni les fonctionnalités mentionnées ci-dessus pour une utilisation interactive. Les observations sont valables à partir de bash 4.2, ksh 93u et mksh 40.9.20120630 telles que trouvées sur Debian Wheezy.

Syntaxe du shell

Citant

$'…'(chaînes littérales avec interpolation antislash) est disponible en ksh93 et ​​mksh. `$"… "(Chaînes traduites) est spécifique à bash.

Constructions conditionnelles

Mksh et ksh93 doivent ;&passer par une casedéclaration, mais pas ;;&pour tester les cas suivants. Mksh a ;|pour cela, et mksh récent permet la ;;&compatibilité.

((…))les expressions et [[ … ]]tests arithmétiques sont des fonctionnalités ksh. Certains opérateurs conditionnels sont différents, voir «expressions conditionnelles» ci-dessous.

Coprocessus

Ksh et bash ont tous deux des coprocessus mais ils fonctionnent différemment.

Les fonctions

Mksh et ksh93 prennent en charge la function name {…}syntaxe des définitions de fonction en plus de la norme name () {…}, mais l'utilisation functiondans ksh modifie les règles de portée, donc respectez la name () …compatibilité. Les règles pour les caractères autorisés dans les noms de fonction varient; s'en tenir aux alphanumériques et _.

Expansion du corset

Ksh93 et ​​mksh prennent en charge l'expansion des accolades {foo,bar}. Ksh93 prend en charge les plages numériques, {1..42}mais pas mksh.

Expansion des paramètres

Soutien ksh93 et mksh extraction de sous - chaînes avec ${VAR:offset}et ${VAR:offset:length}, mais pas la casse comme ${VAR^}, ${VAR,}, etc. Vous pouvez faire la conversion de cas typeset -let typeset -udans les deux bash et ksh.

Ils prennent en charge le remplacement par ${VAR/PATTERN/STRING}ou ${VAR/PATTERN//STRING}. Les règles de citation pour STRING sont légèrement différentes, donc évitez les barres obliques inverses (et peut-être d'autres caractères) dans STRING (créez une variable et utilisez-la à la ${VAR/PATTERN/$REPLACEMENT}place si le remplacement contient des caractères de citation).

Expansion Array ( ${ARRAY[KEY]}, "${ARRAY[@]}", ${#ARRAY[@]}, ${!ARRAY[@]}) travaillent dans bash comme dans ksh.

${!VAR}développer jusqu'à ${OTHERVAR}quand la valeur de VARis OTHERVAR(référence de variable indirecte) est spécifique à bash (ksh fait quelque chose de différent avec ${!VAR}). Pour obtenir cette double expansion dans ksh, vous devez utiliser une référence de nom à la place ( typeset -n VAR=OTHERVAR; echo "$VAR"). ${!PREFIX*}fonctionne de la même manière.

Substitution de processus

Substitution de processus <(…)et >(…)prise en charge dans ksh93 mais pas dans mksh.

Motifs génériques

Les modèles glob étendus ksh qui doivent shopt -s extglobêtre activés dans bash sont toujours disponibles dans ksh93 et ​​mksh.

Mksh ne prend pas en charge les classes de caractères comme [[:alpha:]].

Redirection d'E / S

Bash et ksh93 définissent des pseudo-fichiers et , mais pas mksh./dev/tcp/HOST/PORT/dev/udp/HOST/PORT

L'expansion des caractères génériques dans une redirection dans les scripts (comme dans l' var="*.txt"; echo hello >$aécriture a.txtsi ce nom de fichier est la seule correspondance pour le modèle) est une fonctionnalité spécifique à bash (les autres shells ne le font jamais dans les scripts).

<<< ici les chaînes fonctionnent en ksh comme en bash.

Le raccourci >&pour rediriger les erreurs de syntaxe est également pris en charge par mksh mais pas par ksh93.

Expressions conditionnelles

[[ … ]] syntaxe double parenthèse

La syntaxe du double crochet de ksh est prise en charge par ATT ksh93 et ​​mksh comme dans bash.

Opérateurs de fichiers

Ksh93, mksh et bash prennent en charge les mêmes extensions de POSIX, y compris en -atant que synonyme obsolète de -e, -k(collant), -G(détenu par egid), -O(propriétaire par euid), -ef(même fichier), -nt(plus récent que), -ot(plus ancien que).

-N FILE (modifié depuis la dernière lecture) n'est pas pris en charge par mksh.

Mksh n'a pas d'opérateur de correspondance d'expressions rationnelles =~. Ksh93 a cet opérateur, et il effectue la même correspondance que dans bash, mais n'a pas d'équivalent BASH_REMATCHpour récupérer les groupes correspondants par la suite.

Opérateurs de chaîne

Ksh93 et ​​mksh prennent en charge les mêmes opérateurs de comparaison de chaînes <et >comme bash ainsi que le ==synonyme de =. Mksh n'utilise pas les paramètres régionaux pour déterminer l'ordre lexicographique, il compare les chaînes comme des chaînes d'octets.

Autres opérateurs

-v VARpour tester si une variable est définie est spécifique à bash. Dans n'importe quel shell POSIX, vous pouvez utiliser [ -z "${VAR+1}" ].

Builtins

alias

L'ensemble des caractères autorisés dans les noms d'alias n'est pas le même dans tous les shells. Je pense que c'est la même chose que pour les fonctions (voir ci-dessus).

builtin

Ksh93 a un builtin appelé builtin, mais il n'exécute pas de nom en tant que commande intégrée. Utilisez commandpour contourner les alias et les fonctions; cela appellera un builtin s'il en existe un, sinon une commande externe (vous pouvez éviter cela avec PATH= command error_out_if_this_is_not_a_builtin).

caller

Ceci est spécifique à bash. Vous pouvez obtenir un effet similaire avec .sh.fun, .sh.fileet .sh.linenodans ksh93. En mksh, il y a enfin LINENO.

declare, local,typeset

declareest un nom spécifique à bash pour ksh typeset. Utilisation typeset: ça marche aussi en bash.

Mksh définit localcomme un alias pour typeset. Dans ksh93, vous devez utiliser typeset(ou définir un alias).

Mksh n'a pas de tableaux associatifs (ils sont prévus pour une version encore inédite).

Je ne pense pas qu'il y ait un équivalent exact de bash typeset -t(fonction trace) dans ksh.

cd

Ksh93 n'en a pas -e.

echo

Ksh93 et ​​mksh traitent les options -eet -ncomme dans bash. Mksh comprend également que -Eksh93 ne le traite pas comme une option. L'expansion de barre oblique inverse est désactivée par défaut dans ksh93, activée par défaut dans mksh.

enable

Ksh ne fournit pas un moyen de désactiver les commandes intégrées. Pour éviter une intégration, recherchez le chemin de la commande externe et invoquez-le explicitement.

exec

Ksh93 a -amais pas -l. Mksh n'a ni l'un ni l'autre.

export

Ni ksh93 ni mksh ne l'ont fait export -n. Utilisez à la typeset +x fooplace, cela fonctionne en bash et ksh.

Ksh n'exporte pas de fonctions via l'environnement.

let

let est le même en bash et ksh.

mapfile, readarray

Il s'agit d'une fonctionnalité spécifique à bash. Vous pouvez utiliser des while readboucles ou une substitution de commande pour lire un fichier et le diviser en un tableau de lignes. Prenez soin de vous IFSet globulez. Voici l'équivalent de mapfile -t lines </path/to/file:

IFS=$'\n'; set -f
lines=($(</path/to/file))
unset IFS; set +f

printf

printfest très similaire. Je pense que ksh93 prend en charge toutes les directives de format de bash. mksh ne prend pas en charge %qou %(DATE_FORMAT)T; sur certaines installations, printfn'est pas un module intégré mksh et appelle la commande externe à la place.

printf -v VAR est spécifique à bash, ksh imprime toujours sur la sortie standard.

read

Plusieurs options sont spécifiques à bash, y compris toutes celles concernant readline. Les options -r, -d, -n, -N, -t, -usont identiques dans bash, ksh93 et mksh.

readonly

Vous pouvez déclarer une variable en lecture seule dans Ksh93 et ​​mksh avec la même syntaxe. Si la variable est un tableau, vous devez d'abord l'affecter, puis la rendre en lecture seule avec readonly VAR. Les fonctions ne peuvent pas être rendues en lecture seule dans ksh.

set, shopt

Toutes les options de setet set -osont des fonctionnalités POSIX ou ksh.

shoptest spécifique à bash. De nombreuses options concernent de toute façon une utilisation interactive. Pour les effets sur la globalisation et d'autres fonctionnalités activées par certaines options, consultez la section «Options» ci-dessous.

source

Cette variante de .existe également dans ksh. Dans bash et mksh, sourcerecherche le répertoire courant après PATH, mais dans ksh93, c'est exactement l'équivalent de ..

trap

Le DEBUGpseudo-signal n'est pas implémenté dans mksh. Dans ksh93, il existe avec une manière différente de rapporter les informations, voir le manuel pour plus de détails.

type

Dans ksh, typeest un alias pour whence -v. Dans mksh, type -pn'imprime pas le chemin vers l'exécutable, mais un message lisible par l'homme; vous devez utiliser à la whence -p COMMANDplace.

Les options

shopt -s dotglob - n'ignorez pas les fichiers dot dans le globbing

Pour émuler l' dotgloboption dans ksh93, vous pouvez définir FIGNORE='@(.|..)'. Je ne pense pas qu'il y ait quelque chose comme ça dans mksh.

shopt -s extglob - modèles de glob étendus ksh

L' extgloboption est effectivement toujours activée dans ksh.

shopt -s failglob - erreur si un motif global ne correspond à rien

Je ne pense pas que cela existe dans mksh ou ksh93. Il le fait en zsh (comportement par défaut sauf si null_globou csh_null_globsont définis).

shopt -s globstar**/globbing récursif

Ksh93 a un globbing récursif avec **/, activé avec set -G. Mksh n'a pas de globulation récursive.

shopt -s lastpipe - exécuter la dernière commande d'un pipeline dans le shell parent

Ksh93 exécute toujours la dernière commande d'un pipeline dans le shell parent, qui en bash nécessite que l' lastpipeoption soit définie. Mksh exécute toujours la dernière commande d'un pipeline dans un sous-shell.

shopt -s nocaseglob, shopt -s nocasematch- motifs insensibles à la casse

Mksh n'a pas de correspondance de modèle insensible à la casse. Ksh93 le prend en charge modèle par modèle: préfixez le modèle avec ~(i).

shopt -s nullglob - développer des modèles qui ne correspondent à aucun fichier à une liste vide

Mksh n'a pas ça. Ksh93 le prend en charge modèle par modèle: préfixez le modèle avec ~(N).

Variables

De toute évidence, la plupart des BASH_xxxvariables n'existent pas dans ksh. $BASHPIDpeut être émulé avec le coûteux mais portable sh -c 'echo $PPID', et a été récemment ajouté à mksh. BASH_LINEest .sh.linenoen ksh93 et LINENOen mksh. BASH_SUBSHELLest .sh.subshellen ksh93.

Mksh et ksh93 source tous les deux le fichier donné au ENVdémarrage.

EUIDet UIDn'existent pas dans ksh93. Mksh les appelle USER_IDet KSH_UID; il n'en a pas GROUPS.

FUNCNAMEet FUNCNESTn'existent pas dans ksh. Ksh93 a .sh.funet .sh.level. Les fonctions déclarées avec function foo { …; }(pas de parenthèses!) Ont leur propre nom dans $0.

GLOBIGNOREexiste dans ksh93 mais avec un nom et une syntaxe différents: il est appelé FIGNORE, et c'est un modèle unique, pas une liste séparée par deux-points. Utilisez un @(…|…)modèle. Les subsumes de FIGNOREKsh bash, avec une syntaxe complètement différente.

Ksh93 et ​​mksh n'ont rien de semblable HOSTTYPE, MACHTYPEet OSTYPE. Ni SHELLOPTSou TIMEFORMAT.

Mksh l'a fait PIPESTATUS, mais pas ksh93.

Mksh et ksh93 ont RANDOM.

Gilles 'SO- arrête d'être méchant'
la source
si vous ne voulez pas reproduire correctement la marque (non enregistrée) “mksh” au début d'une phrase ( voir aussi ““ dd. ”” vs. ““ dd ”.” ici ), veuillez écrire “The MirBSD Korn Shell »à la place. Il est toujours faux de mettre en majuscule une lettre de «mksh». Merci.
mirabilos
Comment peut- $BASHPIDon émuler sh -c 'echo $PPID'? J'ai essayé (sh -c 'echo $PPID')dans Bash mais ça me donne le même PID que $$.
Franklin Yu
Je pense que la question convient mieux ici . J'ai copié la question là-bas.
Franklin Yu
4

Cette question est un peu trop large.

Les deux mksh et zsh sont des shells qui prennent en charge de nombreuses extensions spécifiques à GNU bash , mais il y en a toujours qui ne sont pas comprises.

zsh prend en charge plus de choses, mais uniquement dans son mode natif zsh, qui n'est pas compatible avec les shells POSIX (tels que GNU bash, AT&T ksh93 , mksh). De plus, mksh est beaucoup plus léger, plus rapide et plus portable.

En général, si ce sont vos scripts dont nous parlons, allez-y, testez-les simplement. (mksh ne prend pas encore en charge les tableaux associatifs de style bash4. La commande "declare" est spécifique à bash, "typeset" est un équivalent. Je ne connais pas suffisamment zsh pour dire quoi que ce soit à ce sujet. ksh93 n'a pas "local" mais utilise également "typeset" pour cela.) Mais s'il s'agit, par exemple, d'exécuter un système Debian sans bash, oubliez-le. L'existence de bash fait partie de la «promesse» (API / ABI du système) et en dépend beaucoup.

Avertissement: je suis le développeur mksh.

mirabilos
la source
1

Comparaison des coques ZSH

Ces dernières années, il y a cependant eu un certain chevauchement dans les extensions. Zsh (à partir de 3.1.6) a ${var/old/new}' feature for replacing the text old with the text new in the parameter $var. Note one difference here: while both shells implement the syntax$ {var / # old / new} 'et ${var/%old/new}' for anchoring the match of old to the start or end of the parameter text, respectively, in zsh you can't put the#' ou %' inside a parameter: in other words{var / $ old / new} ' bash où old commence par un #' treats that as an ordinary character in zsh, unlike bash. To do this sort of thing in zsh you can use (from 3.1.7) the new syntax for anchors in any pattern,(#s)' pour correspondre au début d'une chaîne et `(#e) 'pour correspondre à la fin. Ceux-ci nécessitent la définition de l'option EXTENDED_GLOB.

Je ne connais pas très bien mksh, donc je ne sais pas où chercher cette réponse.

Si vous recherchez un remplacement sécurisé pour le shell, aucun de ces shells ne diffère beaucoup de Bash en ce qui concerne le défaut inhérent dont vous parlez.

Un langage comme Perl gère les entrées de manière plus sécurisée. Mais la maintenabilité est également essentielle ici. Le remplacement de la coque Perl n'est pas très bien adopté. Il incombe au responsable du shell de gérer les entrées en toute sécurité. Alors quand vous écrivez des scripts, validez, validez, validez tout! Utilisez des contrats de code pour garantir des résultats corrects à chaque fois!

Coquille Perl

Déclaration de la FSF sur Shell Shock

Tyler Maginnis
la source
S'il est vraiment vrai que d'autres shells ont le même défaut - ce dont je doute quelque peu, d'après ce que j'ai vu - alors c'est un problème ÉNORME , car beaucoup de programmes tiers transmettent des variables au shell sans aucune sorte de validation ou quoi que ce soit. Si tel est le cas, nous pourrions aussi bien rejeter POSIX entièrement.
DanL4096
1
Le projet Bash a connu 1 exploit de 0 jour en 10 ans. Microsoft Windows a plus de 10 exploits, tous les 0 jours, par semaine. Savez-vous même combien de personnes ont dérangé l'équipe de développement Bash à ce sujet? Mettez-le à jour et continuez! Ce n'est pas grand chose.
Tyler Maginnis
1
@ DanL4096. Passer des variables à des scripts shell qui ne font alors pas suffisamment de vérification de la validité des variables n'est pas une raison pour rejeter POSIX. Le problème réside dans la personne qui a écrit le script shell en premier lieu.
fpmurphy
0

L' historique du shell n'est pas activé par défaut dans mksh.

  • Dans votre .mkshrcensemble juste:

    export HISTFILE=~/.mksh-history

Stuart Cardall
la source