GNU/Linux >> Tutoriels Linux >  >> Linux

Pourquoi Printf est-il meilleur qu'Echo ?

J'ai entendu dire que printf vaut mieux que echo . Je ne me souviens que d'un seul cas de mon expérience où j'ai dû utiliser printf parce que echo n'a pas fonctionné pour alimenter du texte dans un programme sur RHEL 5.8 mais printf a fait. Mais apparemment, il existe d'autres différences, et j'aimerais savoir quelles sont-elles ainsi que s'il existe des cas spécifiques dans lesquels utiliser l'une par rapport à l'autre.

Réponse acceptée :

Fondamentalement, c'est 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 "nt" pour afficher les caractères de nouvelle ligne ou de tabulation, ou avoir la possibilité de ne pas afficher le caractère de fin de ligne.

Ils ont ensuite réfléchi plus sérieusement mais au lieu d'ajouter cette fonctionnalité au shell (comme perl où entre guillemets doubles, t signifie en fait un caractère de tabulation), ils l'ont ajouté à echo .

David Korn s'est rendu compte de l'erreur et a introduit une nouvelle forme de guillemets :$'...' qui a ensuite été copié par bash et zsh mais il était bien trop tard à ce moment-là.

Maintenant, lorsqu'un echo UNIX standard reçoit un argument qui contient les deux caractères et t , au lieu de les sortir, il sort un caractère de tabulation. Et dès qu'il voit c dans un argument, il arrête de sortir (donc la nouvelle ligne de fin n'est pas sortie non plus).

D'autres shells/éditeurs/versions Unix ont choisi de le faire différemment :ils ont ajouté un -e option pour développer les séquences d'échappement, et un -n option pour ne pas afficher la nouvelle ligne de fin. Certains ont un -E pour désactiver les séquences d'échappement, certains ont -n mais pas -e , la liste des séquences d'échappement supportées par un echo la mise en œuvre n'est pas nécessairement la même que celle prise en charge par un 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 prise en charge d'un -- pour marquer la fin des options (le echo certains shells non similaires à Bourne le font, et zsh prend en charge - pour cela cependant), donc par exemple, il est difficile de sortir "-n" avec echo dans de nombreux coquillages.

Sur certains shells comme bash ¹ ou ksh93 ² ou yash ($ECHO_STYLE variable), le comportement dépend même de la façon dont le shell a été compilé ou de l'environnement (GNU echo Le comportement de va également changer si $POSIXLY_CORRECT est dans l'environnement et avec la version, zsh 's avec son bsd_echo option, certains basés sur pdksh avec leur posix option ou s'ils sont appelés comme sh ou pas). Donc deux bash echo s, même à partir de la même version de bash ne sont pas garantis de se comporter de la même manière.

POSIX dit :si le premier argument est -n ou tout argument contient des barres obliques inverses, alors le comportement n'est pas spécifié . bash echo à cet égard n'est pas POSIX dans la mesure où par exemple echo -e n'affiche pas -e<newline> comme POSIX l'exige. La spécification UNIX est plus stricte, elle interdit -n et nécessite l'expansion de certaines séquences d'échappement, y compris le c un pour 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 certifiés les systèmes comme macOS ne sont pas compatibles.

Pour vraiment représenter la réalité actuelle, POSIX devrait en fait dire :si le premier argument correspond au ^-([eEn]*|-help|-version)$ une expression rationnelle étendue ou tout argument contient des barres obliques inverses (ou des caractères dont l'encodage contient l'encodage du caractère barre oblique inverse comme α dans les locales utilisant le jeu de caractères BIG5), alors le comportement n'est pas spécifié.

Dans l'ensemble, vous ne savez pas ce que echo "$var" sortira sauf si vous pouvez vous assurer que $var ne contient pas de barres obliques inverses et ne commence pas par - . La spécification POSIX nous dit en fait d'utiliser printf à la place dans ce cas.

Donc, cela signifie 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 une entrée externe (de l'utilisateur comme arguments, ou des noms de fichiers du système de fichiers…), vous ne pouvez pas utiliser echo pour l'afficher.

C'est OK :

echo >&2 Invalid file.

Ce n'est pas :

echo >&2 "Invalid file: $file"

(Bien que cela fonctionnera bien avec certains echo (non conformes à UNIX) implémentations comme bash c'est quand le xpg_echo l'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).

En relation :Traiter chaque ligne de sortie de `ping` immédiatement dans le pipeline ?

file=$(echo "$var" | tr ' ' _) n'est pas OK dans la plupart des implémentations (les exceptions étant yash avec ECHO_STYLE=raw (avec la mise en garde que yash Les variables de 's ne peuvent pas contenir de séquences arbitraires d'octets, donc pas de noms de fichiers arbitraires) et zsh echo -E - "$var" ).

printf , en revanche est plus fiable, du moins lorsqu'il se limite à l'utilisation basique de echo .

printf '%sn' "$var"

Affichera le contenu de $var suivi d'un caractère de saut de ligne, quel que soit le caractère qu'il peut contenir.

printf '%s' "$var"

Le sortira sans le caractère de fin de ligne.

Maintenant, il y a aussi des différences entre printf implémentations. Il y a un noyau de fonctionnalités qui est spécifié par POSIX, mais il y a aussi beaucoup d'extensions. Par exemple, certains supportent un %q pour citer les arguments, mais la façon dont c'est fait varie d'un shell à l'autre, certains prennent en charge uxxxx pour les caractères unicode. Le comportement varie pour printf '%10sn' "$var" dans les locales multi-octets, il y a au moins trois résultats différents pour printf %b '123'

Mais au final, si vous vous en tenez à l'ensemble de fonctionnalités POSIX de printf et n'essayez pas de faire quelque chose de trop fantaisiste avec, vous n'aurez plus d'ennuis.

Mais rappelez-vous que le premier argument est le format, il ne doit donc pas contenir de données variables/incontrôlées.

Un echo plus fiable peut être implémenté en utilisant printf , comme :

echo() ( # subshell for local scope for $IFS
  IFS=" " # needed for "$*"
  printf '%sn' "$*"
)

echo_n() (
  IFS=" "
  printf %s "$*"
)

echo_e() (
  IFS=" "
  printf '%bn' "$*"
)

Le sous-shell (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 avec plusieurs coques, ou en l'écrivant comme :

echo() {
  if [ "$#" -gt 0 ]; then
     printf %s "$1"
     shift
     if [ "$#" -gt 0 ]; then
       printf ' %s' "[email protected]"
     fi
  fi
  printf 'n'
}

Remarques

1. comment bash echo le comportement peut être modifié.

Avec bash , au moment de l'exécution, il y a deux choses qui contrôlent le comportement de echo (à côté de enable -n echo ou redéfinir echo en tant que fonction ou alias) :
le xpg_echo bash option et si bash est en mode posix. posix le mode peut être activé si bash s'appelle sh ou si POSIXLY_CORRECT est dans l'environnement ou avec le posix choix :

Comportement par défaut sur la plupart des systèmes :

$ bash -c 'echo -n "
Linux
  1. [Linux] :Diagnostiquer les problèmes de réseau à l'aide de MTR - mieux que traceroute !

  2. Pourquoi le tilde (~) ne se développe-t-il pas à l'intérieur des guillemets doubles ?

  3. Pourquoi un VPS Linux est-il un meilleur choix qu'un VPS Windows

  4. Lzma Vs Bzip2 - Meilleure compression que bzip2 sous UNIX / Linux

  5. Linux Vs Windows - Pourquoi Linux est meilleur pour la programmation et le développement Web

8 raisons pour lesquelles Linux Mint est meilleur qu'Ubuntu pour les débutants Linux

11 raisons pour lesquelles Linux est meilleur que Windows

Linux vs Mac :7 raisons pour lesquelles Linux est un meilleur choix que Mac

Pourquoi Linux est-il si mauvais et Windows 11 meilleur à tous points de vue ?

echo caractère de nouvelle ligne ne fonctionne pas dans bash

Pourquoi le mot de passe 'sudo' est-il différent du mot de passe 'su root'