Certaines personnes ont cette notion erronée qui readest la commande de lire une ligne. Ce n'est pas.
readlit les mots d'une ligne (éventuellement d'une barre oblique inversée), où les mots sont $IFSdélimités et une barre oblique inverse peut être utilisée pour échapper aux délimiteurs (ou aux lignes continues).
La syntaxe générique est la suivante:
read word1 word2... remaining_words
readlit stdin un octet à la fois jusqu'à ce qu'il trouve un caractère de saut de ligne sans échappement (ou de fin d'entrée), qui se divise selon des règles complexes et stocke le résultat de cette division en $word1, $word2... $remaining_words.
Par exemple sur une entrée comme:
<tab> foo bar\ baz bl\ah blah\
whatever whatever
et avec la valeur par défaut de $IFS, read a b cattribuerait:
$a ⇐ foo
$b ⇐ bar baz
$c ⇐ blah blahwhatever whatever
Maintenant, si on ne passe qu'un seul argument, cela ne devient pas read line. C'est encore read remaining_words. Le traitement de la barre oblique inverse est toujours effectué, les caractères IFS sont toujours supprimés au début et à la fin.
L' -roption supprime le traitement des barres obliques inverses. Donc, cette même commande ci-dessus avec -rau lieu d'attribuer
$a ⇐ foo
$b ⇐ bar\
$c ⇐ baz bl\ah blah\
Maintenant, pour la partie scission, il est important de comprendre qu’il existe deux classes de caractères $IFS: les caractères IFS blancs (à savoir, espace et tabulation (et newline, bien que cela ne soit pas important sauf si vous utilisez -d), ce qui se produit également. être dans la valeur par défaut de $IFS) et les autres. Le traitement de ces deux classes de caractères est différent.
Avec IFS=:( :étant pas un caractère IFS des espaces), une entrée comme :foo::bar::serait divisé en "", "foo", "", baret ""(et un supplément ""avec certaines implémentations si cela ne importe pas , sauf pour read -a). Tandis que si nous remplaçons cela :par de l’espace, la division se fait uniquement en fooet bar. C’est-à-dire que les principales et les dernières sont ignorées et que leurs séquences sont traitées comme une seule. Il existe des règles supplémentaires lorsque des espaces et des caractères non-blancs sont combinés $IFS. Certaines implémentations peuvent ajouter / supprimer le traitement spécial en doublant les caractères dans IFS ( IFS=::ou IFS=' ').
Donc, ici, si nous ne voulons pas que les caractères d’espace blanc qui restent et qui ne soient pas échappés soient supprimés, nous devons supprimer ces caractères d’espace blanc IFS de IFS.
Même avec les caractères IFS-non-blancs, si la ligne d’entrée contient un (et un seul) de ces caractères et que c’est le dernier caractère de la ligne (comme IFS=: read -r wordsur une entrée similaire foo:) avec des shells POSIX ( zshni certaines pdkshversions), cette entrée est considéré comme l' un foomot parce que dans ces coquilles, les caractères $IFSsont considérés comme terminateurs , donc wordcontiendra foo, non foo:.
Ainsi, la manière canonique de lire une ligne d’entrée avec l’ readintégré est:
IFS= read -r line
(notez que pour la plupart des readimplémentations, cela ne fonctionne que pour les lignes de texte car le caractère NUL n'est pas pris en charge, sauf dans zsh).
L'utilisation de la var=value cmdsyntaxe permet de s'assurer IFSque le paramétrage est différent pour la durée de cette cmdcommande.
Note d'histoire
Le readconstruit a été introduit par le shell Bourne et devait déjà lire des mots , pas des lignes. Il existe quelques différences importantes avec les coques POSIX modernes.
Le shell Bourne readne prenant pas en charge une -roption (introduite par le shell Korn), il n’ya donc aucun moyen de désactiver le traitement des barres obliques inverses autrement que de prétraiter l’entrée avec quelque chose de similaire sed 's/\\/&&/g'.
Le shell Bourne n'avait pas cette notion de deux classes de caractères (qui a de nouveau été introduite par ksh). Dans le Bourne shell tous les personnages subissent le même traitement que IFS Espaces blancs font ksh, qui est IFS=: read a b csur une entrée comme foo::barattribuerait barà $b, pas la chaîne vide.
Dans le shell Bourne, avec:
var=value cmd
Si cmdest intégré (comme l' readest), varreste défini valueaprès la cmdfin. C’est particulièrement critique $IFScar dans le shell Bourne, tout $IFSest utilisé, pas seulement les extensions. De même, si vous supprimez le caractère d'espacement $IFSdans le shell Bourne, cela "$@"ne fonctionnera plus.
Dans le shell Bourne, la redirection d’une commande composée l’exécute dans un sous-shell (dans les versions les plus anciennes, même si cela ne fonctionnait pas read var < fileou exec 3< file; read var <&3ne fonctionnait pas). Il était donc rare que le shell Bourne soit utilisé readpour autre chose que la saisie de l’utilisateur sur le terminal. (où le traitement de continuation de ligne était logique)
Certains Unices (comme HP / UX, il y en a aussi un util-linux) ont toujours une linecommande pour lire une ligne d’entrée (une commande UNIX standard jusqu’à la spécification Single UNIX version 2 ).
C'est fondamentalement la même chose, head -n 1sauf qu'elle lit un octet à la fois pour s'assurer qu'elle ne lit pas plus d'une ligne. Sur ces systèmes, vous pouvez faire:
line=`line`
Bien sûr, cela signifie créer un nouveau processus, exécuter une commande et lire sa sortie via un tube, ce qui est beaucoup moins efficace que celui de ksh IFS= read -r line, mais toujours beaucoup plus intuitif.