J'ai entendu dire que printf
c'est mieux que echo
. Je ne me souviens que de mon expérience, où je devais utiliser, printf
car echo
cela ne fonctionnait pas pour insérer du texte dans un programme sur RHEL 5.8, mais ce fut le printf
cas. Mais apparemment, il existe d’autres différences, et je voudrais demander en quoi elles consistent et s’il existe des cas spécifiques dans lesquels utiliser l’un ou l’autre.
text-processing
echo
printf
amphibient
la source
la source
echo -e
?echo -e
ne fonctionne pas danssh
, mais dansbash
(pour une raison quelconque), et docker, par exemple, utilisesh
par défaut pour sesRUN
commandesecho -e
pour moi fonctionne dans Android Terminal, qui est essentiellementsh
.Réponses:
Fondamentalement, il s’agit d’un problème de portabilité (et de fiabilité).
Initialement,
echo
n’a accepté aucune option et n’a rien développé. Tout ce qu'il faisait était de sortir ses arguments séparés par un espace et terminés par un caractère de nouvelle ligne.Maintenant, quelqu'un a pensé que ce serait bien si nous pouvions faire des choses comme
echo "\n\t"
sortir des caractères de nouvelle ligne ou de tabulation, ou avoir une option pour ne pas afficher le dernier caractère de nouvelle ligne.Ils ont alors pensé plus fort, mais au lieu d’ajouter cette fonctionnalité au shell (comme à l’
perl
intérieur de guillemets, cela\t
signifie en fait un caractère de tabulation), ils l’ont ajoutéeecho
.David Korn a pris conscience de l’erreur et a introduit une nouvelle forme de guillemets:
$'...'
elle a ensuite été copiée parbash
etzsh
mais c’était beaucoup trop tard à cette époque.Désormais, lorsqu'un UNIX standard
echo
reçoit un argument contenant les deux caractères\
ett
, au lieu de les générer, il génère un caractère de tabulation. Et dès qu’il voit\c
un argument, il arrête la sortie (la nouvelle ligne finale n’est donc pas sortie non plus).D'autres shells / fournisseurs / versions d'Unix ont choisi de le faire différemment: ils ont ajouté une
-e
option permettant de développer les séquences d'échappement et une-n
option permettant de ne pas afficher le retour à la ligne final. Certains ont la-E
possibilité de désactiver les séquences d'échappement, d'autres-n
non mais-e
la liste des séquences d'échappement prises en charge par uneecho
implémentation n'est pas nécessairement la même que celle prise en charge par une autre.Sven Mascheck a une belle page qui montre l'étendue du problème .
Sur ces
echo
implémentations qui prennent en charge les options, il n'y a généralement pas de soutien d'un--
pour marquer la fin des options (leecho
builtin de quelques obus non Bourne comme le font, et zsh soutient-
pour que , bien), de sorte que , par exemple, il est difficile de sortie"-n"
avececho
en beaucoup d'obus.Sur certains shells comme
bash
¹ ouksh93
² ouyash
($ECHO_STYLE
variable), le comportement dépend même de la manière dont le shell a été compilé ou de l'environnement (echo
le comportement de GNU changera également s'il$POSIXLY_CORRECT
est dans l'environnement et avec la version 4 ,zsh
avec sonbsd_echo
option, certains basés sur pdksh avec leurposix
option ou s’ils sont appelés commesh
ou non). Donc, deuxbash
echo
, même de la même version de,bash
ne se comportent pas de la même manière.POSIX dit: si le premier argument est
-n
ou si l'un des arguments contient des barres obliques inverses, le comportement n'est pas spécifié .bash
echo à cet égard n’est pas POSIX dans la mesure où, par exemple,echo -e
ne produit pas-e<newline>
comme POSIX le requiert. La spécification UNIX est plus stricte, elle interdit-n
et nécessite le développement de certaines séquences d'échappement, y compris\c
celle destinée à arrêter la sortie.Ces spécifications ne viennent pas vraiment à la rescousse ici étant donné que de nombreuses implémentations ne sont pas conformes. Même certains systèmes certifiés tels que macOS 5 ne sont pas conformes.
Pour représenter réellement la réalité actuelle, POSIX devrait en réalité indiquer : si le premier argument correspond à l'
^-([eEn]*|-help|-version)$
expression rationnelle étendue ou si l'un des arguments contient des barres obliques inverses (ou des caractères dont le codage contient le codage du caractère de la barre oblique inversée commeα
dans les paramètres régionaux utilisant le jeu de caractères BIG5), le comportement non spécifié.Globalement, vous ne savez pas ce qui
echo "$var"
sera généré à moins que vous ne puissiez vous assurer qu'il$var
ne contient pas de caractère barre oblique inverse et ne commence pas par-
. La spécification POSIX nous dit effectivement d’utiliserprintf
plutôt dans ce cas.Cela signifie donc que vous ne pouvez pas utiliser
echo
pour afficher des données non contrôlées. En d'autres termes, si vous écrivez un script et qu'il prend des entrées externes (de l'utilisateur sous forme d'arguments, ou des noms de fichiers du système de fichiers ...), vous ne pouvez pas utiliserecho
pour l'afficher.C'est acceptable:
Ce n'est pas:
(Bien que cela fonctionne correctement avec certaines
echo
implémentations (non compatibles UNIX) telles quebash
lorsque l'xpg_echo
option n'a pas été activée d'une manière ou d'une autre, comme au moment de la compilation ou via l'environnement).file=$(echo "$var" | tr ' ' _)
n'est pas OK dans la plupart des implémentations (exceptions étantyash
avecECHO_STYLE=raw
(la mise en garde queyash
« les variables s ne peuvent pas contenir des séquences arbitraires d'octets afin de ne pas les noms de fichiers arbitraires) etzsh
» secho -E - "$var"
6 ).printf
, d’autre part, est plus fiable, du moins quand il est limité à l’utilisation de base deecho
.Affiche le contenu de
$var
suivi d'un caractère de nouvelle ligne, quel que soit le caractère qu'il peut contenir.Le produira sans le caractère de fin de ligne suivant.
Maintenant, il y a aussi des différences entre les
printf
implémentations. POSIX spécifie un noyau de fonctionnalités, mais il existe ensuite de nombreuses extensions. Par exemple, certains prennent en charge%q
les arguments, mais la manière de procéder varie d’un shell à l’autre, certains\uxxxx
prenant en charge les caractères unicode. Le comportement varieprintf '%10s\n' "$var"
dans les environnements locaux multi-octets, il existe au moins trois résultats différents pourprintf %b '\123'
Mais à la fin, si vous vous en tenez à l'ensemble des fonctionnalités POSIX
printf
et que vous n'essayez rien de trop fantaisiste, vous ne rencontrerez aucun problème.Mais rappelez-vous que le premier argument est le format, il ne devrait donc pas contenir de données variables / non contrôlées.
Un plus fiable
echo
peut être mis en œuvre en utilisantprintf
, comme:Le sous-shell (ce qui implique de générer un processus supplémentaire dans la plupart des implémentations de shell) peut être évité en utilisant
local IFS
plusieurs shell, ou en l'écrivant comme ceci:Remarques
1. comment
bash
leecho
comportement peut être modifié.Avec
bash
, au moment de l'exécution, deux éléments contrôlent le comportement deecho
(à côté de laenable -n echo
redéfinition enecho
tant que fonction ou alias): l'xpg_echo
bash
option et lebash
mode posix.posix
Le mode peut être activé sibash
est appelé en tant quesh
ou si sePOSIXLY_CORRECT
trouve dans l'environnement ou avec l'posix
option:Comportement par défaut sur la plupart des systèmes:
xpg_echo
étend les séquences car UNIX requiert:Il honore encore
-n
et-e
(et-E
):Avec
xpg_echo
et en mode POSIX:Cette fois,
bash
est conforme à la fois à POSIX et à UNIX. Notez qu'en mode POSIX, ilbash
n'est toujours pas conforme à POSIX car il ne sort pas-e
en:Les valeurs par défaut pour xpg_echo et posix peuvent être définies lors de la compilation avec les options
--enable-xpg-echo-default
et--enable-strict-posix-default
duconfigure
script. C'est typiquement ce que les versions récentes d'OS / X font pour construire leurs/bin/sh
.Pas de mise en œuvre / la distribution Unix / Linux dans leur esprit serait généralement faire pour. En fait, ce n'est pas vrai, le produit/bin/bash
bien/bin/bash
fourni par Oracle avec Solaris 11 (dans un package facultatif) semble être construit--enable-xpg-echo-default
(ce qui n'était pas le cas dans Solaris 10).2. Comment
ksh93
leecho
comportement peut être modifié.Dans
ksh93
, le fait d'echo
étendre les séquences d'échappement ou non et de reconnaître les options dépend du contenu des variables d'environnement$PATH
et / ou$_AST_FEATURES
.S'il
$PATH
contient un composant qui contient/5bin
ou/xpg
avant le composant/bin
ou/usr/bin
, il se comporte de la manière SysV / UNIX (développe les séquences, n'accepte pas les options). S'il trouve/ucb
ou/bsd
premier ou si$_AST_FEATURES
7 contientUNIVERSE = ucb
, alors il se comporte de la manière BSD 3 (-e
pour permettre l'expansion, reconnaît-n
).La valeur par défaut dépend du système, BSD sous Debian (voir le résultat
builtin getconf; getconf UNIVERSE
dans les versions récentes de ksh93):3. BSD pour echo -e?
La référence à BSD pour le traitement de l'
-e
option est un peu trompeuse ici. La plupart de cesecho
comportements différents et incompatibles ont tous été introduits chez AT & T:\n
,\0ooo
,\c
Dans le banc de travail du programmeur UNIX (basé sur Unix V6), et le reste (\b
,\r
...) dans Unix System III Réf .-n
sous Unix V7 (par Dennis Ritchie Ref )-e
sous Unix V8 (par Dennis Ritchie Ref )-E
elle-même provient peut-être initialement debash
(CWRU / CWRU.chlog dans la version 1.13.5 mentionne l’ajout de Brian Fox le 1992-10-18, GNU leecho
copiant peu de temps après dans sh-utils-1.8 publié 10 jours plus tard)Alors que le
echo
builtin dessh
ou BSDs ont soutenu-e
depuis le jour où ils ont commencé à utiliser le shell Almquist pour elle au début des années 90, la version autonomeecho
utilitaire à ce jour ne supporte pas là ( FreeBSDecho
ne supporte toujours pas-e
, même si elle prend en charge-n
comme Unix V7 (et aussi\c
mais seulement à la fin du dernier argument)).La manipulation de
-e
a été ajouté àksh93
« secho
quand dans le BSD univers dans la version ksh93r sorti en 2006 et peut être désactivé au moment de la compilation.4. GNU echo changement de comportement en 8.31
Depuis coreutils 8.31 (et cette validation ), GNU
echo
étend désormais les séquences d'échappement par défaut lorsque POSIXLY_CORRECT est dans l'environnement, afin de correspondre au comportement debash -o posix -O xpg_echo
la commandeecho
intégrée de s (voir le rapport de bogue ).5. macOS
echo
La plupart des versions de macOS ont reçu la certification UNIX de OpenGroup .
Leur version
sh
intégréeecho
est conforme car elle estbash
(une très ancienne version) construite avecxpg_echo
activé par défaut, mais leurecho
utilitaire autonome ne l’est pas.env echo -n
ne sort rien au lieu de-n<newline>
,env echo '\n'
sort\n<newline>
au lieu de<newline><newline>
.C’est
/bin/echo
celui de FreeBSD qui supprime la sortie de nouvelle ligne si le premier argument est-n
ou (depuis 1995) si le dernier argument se termine par\c
, mais ne supporte aucune autre séquence de barre oblique inverse requise par UNIX, même\\
.6. des
echo
implémentations qui peuvent produire des données arbitraires telles quellesÀ proprement parler, vous pourriez aussi compter que FreeBSD / macOS
/bin/echo
ci-dessus (et non dans le shell de leur shellecho
) oùzsh
secho -E - "$var"
ouyash
'sECHO_STYLE=raw echo "$var"
(printf '%s\n' "$var"
) pourrait être écrit:Les mises en œuvre qui prennent en charge
-E
et-n
(ou peuvent être configurées pour) peuvent également faire:Et
zsh
« secho -nE - "$var"
(printf %s "$var"
) peuvent être écrites7.
_AST_FEATURES
et l'ASTUNIVERSE
Il
_AST_FEATURES
n'est pas destiné à être manipulé directement, il est utilisé pour propager les paramètres de configuration AST lors de l'exécution de commandes. La configuration doit être effectuée via l'astgetconf()
API (non documentée) . À l’intérieurksh93
, l’getconf
intégré (activé avecbuiltin getconf
ou par appelcommand /opt/ast/bin/getconf
) est l’interface pourastgetconf()
Par exemple, vous feriez
builtin getconf; getconf UNIVERSE = att
changer leUNIVERSE
réglage enatt
(faisantecho
se comporter de manière SysV entre autres). Après cela, vous remarquerez que la$_AST_FEATURES
variable d’environnement contientUNIVERSE = att
.la source
echo
développer les\x
séquences par opposition au shell dans le cadre de la syntaxe de citation est que vous pouvez alors générer un octet NUL chaînes, où la moitié des appels système (commeexecve()
) ne peuvent pas prendre de séquences d'octets arbitraires)printf
semble même poser problème, car la plupart des implémentations le font mal. La seule implémentation correcte que je connaisse se trouve dansbosh
et la page de Sven Maschek ne répertorie pas les problèmes liés aux octets nuls via\0
.Vous voudrez peut-être utiliser
printf
pour ses options de formatage.echo
est utile pour imprimer la valeur d’une variable ou d’une ligne (simple), mais c’est tout.printf
peut fondamentalement faire ce que la version C de celui-ci peut faire.Exemple d'utilisation et de capacités:
Echo
:printf
:Sources:
la source
echo
pour imprimer une variable peut échouer si la valeur de la variable contient des méta-caractères.Un "avantage", si vous voulez l'appeler ainsi, serait que vous n'avez pas à le dire comme
echo
à interpréter certaines séquences d'échappement telles que\n
. Il sait les interpréter et n'exige pas-e
de le faire.(NB: le dernier
\n
est nécessaire,echo
implique, sauf si vous donnez l'-n
option)contre
Notez le dernier
\n
dansprintf
. A la fin de la journée , il est une question de goût et les exigences que vous utilisez:echo
ouprintf
.la source
/usr/bin/echo
et lebash
intégré. Le paramètredash
,ksh
etzsh
intégréecho
n'a pas besoin de-e
commutateur pour développer des caractères d' échappement avec une barre oblique inversée.printf '%s\n' 'foo\bar
.Les performances sont un inconvénient
printf
car le shell intégréecho
est beaucoup plus rapide. Cela entre en jeu en particulier dans Cygwin où chaque instance d'une nouvelle commande entraîne une surcharge de Windows. Lorsque j'ai modifié mon programme d'écho-lourd en utilisant/bin/echo
écho du shell, les performances ont presque doublé. C'est un compromis entre portabilité et performance. Ce n'est pas un slam dunk à toujours utiliserprintf
.la source
printf
est construit dans la plupart des shells de nos jours (bash, dash, ksh, zsh, yash, certains dérivés de pdksh ... inclut donc les shells que l'on trouve généralement sur cygwin). Les seules exceptions notables sont certainspdksh
dérivés.printf
pour générer des octets nuls, mais certaines implémentations interprètent "\ c" dans la chaîne de format, même si elles ne le devraient pas.printf
n'est pas spécifié par POSIX si vous utilisez\c
la chaîne de formatage, ainsi lesprintf
implémentations peuvent faire ce qu'elles veulent à cet égard. Par exemple, certains le traitent de la même manière que dans PWBecho
(provoque la fermeture de printf), ksh l'utilise pour\cA
les caractères de contrôle (pour l'argument de format printf et pour$'...'
mais pas pourecho
niprint
!). Je ne sais pas ce que cela a à voir avec l' impression d' octets NUL, ou peut - être vous référant àksh
l »printf '\c@'
?