Je ne comprends pas la deuxième ligne. Je pensais que lire les variables de lecture. L'écho de commande est étrange aussi. Pourriez-vous expliquer?
diego9403
Je ne suis pas un expert Unix, mais je pense que la deuxième ligne lit les choses otherfileet echoles diffuse file. Il crée également des variables à partir de ce qu'il lit. Si vous souhaitez une réponse définitive, posez votre propre question.
DavidPostill
2
@ diego9403: readreçoit les entrées de stdin. Seul, il lirait ce que vous tapez. Puisque stdin a été redirigé vers, <otherfilele contenu de otherfile"est saisi" dans stdin. Donc, readobtient les valeurs ligne par ligne dans les variables $ A, $ B, $ C, $ D et $ E.
slebetman
Donc, c'est juste une alternative plus obscure à truncatepartir de coreutils?
Federico Poloni
1
@PeterCordes Je ne voulais pas dire "obscur" comme dans "c'est inhabituel", mais comme dans "c'est moins clair pour le lecteur".
Federico Poloni
29
Cela ressemble à une manière élégante de créer un nouveau fichier. In bash:est une commande nulle:
$ type :: is a shell builtin
$ help ::::Null command.No effect; the command does nothing.ExitStatus:Always succeeds.
Il tronquera également le fichier s'il existe déjà ...
DavidPostill
2
oui, c'est ce qui >fait
Arkadiusz Drabczyk
2
:est un raccourci pour true. Peut-être dans certains coquillages, trueun incorporé? Les deux sont intégrés à bash.
Peter Cordes
12
:est un autre nom pour true. Les deux sont des commandes shell dans bash, mais non /bin/:, seulement un /bin/true. La redirection de sortie entraîne le shell dans open(2)le fichier avec O_CREAT|O_TRUNC. Si rien n'est écrit, il reste à la longueur zéro.
Assembler ces deux éléments :> fileest un idiome assez courant pour tronquer des fichiers. La plupart des gens essaient cependant de rendre cela moins étrange en écrivant : >file.
Comme vous avez demandé dans un commentaire sur la deuxième ligne, je vais transformer mes commentaires en réponse. (même si vous ne l'avez pas demandé dans votre question.)
La deuxième ligne est une boucle qui lit les lignes otherfiledans certaines variables nommées. Le corps de la boucle les utilise echopour les imprimer avec des ;séparateurs au lieu des espaces qu’ils avaient auparavant. fileest fermé et rouvert (pour ajouter) chaque itération, car la redirection est à l'intérieur de la boucle. L'utilisation while ...;do read -r ...;done <otherfile >fileserait moins efficace, et éviterait de tronquer le fichier en premier. read -rne mange pas \comme un personnage d'évasion.
Le traitement du texte à bash est assez lent. Une partie de cela est inévitable: readdoit aller un octet à la fois (un read(2)appel système par octet) pour éviter de dépasser la fin d'une ligne. Il serait préférable d'utiliser le bon outil pour le travail:
--signifie que votre script ne casse pas si otherfileon lui donne un nom idiot --version.
Définir le séparateur de champ de sortie sur ;signifie que vous pouvez simplement transmettre plusieurs champs en tant qu'arguments à imprimer. Shell readattribue le reste de la ligne avec les espaces à la dernière variable, mais il n’ya aucun moyen de dire à awk de se scinder uniquement en 5. Si cela est important, continuez simplement à utiliser une boucle bash, car c’est gênant dans awk. Perl facilite cela, car il splitpeut prendre beaucoup d'arguments, mais il est beaucoup plus lent à démarrer que awk.
En fait, ce n’était pas si difficile, c’était juste une regex laide à écrire. Pour obtenir le reste de la ligne au lieu d' $5awk, le bouclage sur les champs perd leur espace d'origine. Ma première idée viable est d'utiliser gensubsur $0(toute la ligne) pour supprimer les 4 premiers champs (c'est-à-dire les non-espaces suivis par des espaces), en laissant tout le reste:
J'ai eu raison dès le premier essai, mais le fait d'être impressionné par moi en dit long sur la lisibilité de ce code awk. >. <
Notez comme c'est le même printqu'auparavant, mais tailà la place de $5.
echo 'A B c DD e f g f'|
awk -vOFS=\; '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1);
print $1, $2, $4, tail, $3 }'
A;B;DD;e f g f;c
Ce serait plus impressionnant si je pouvais copier / coller le littéral et montrer que cela venait dans la sortie. Tapez un en bash avec ^ Q. ctrl-Q signifie Citer la touche suivante en tant que caractère littéral, car l'édition des lignes de style emacs de bash est identique à celle d'emacs.
http://mywiki.wooledge.org/BashFAQ contient des informations utiles sur les scripts d'une manière qui ne casse pas les données ou les noms de fichiers que vous envoyez au script.
:>
n'est pas un seul opérateur. Il sera peut-être plus facile de comprendre si vous le lisez tel quel: > file
.while read A B C D E; do echo "$A;$B;$D;$E;$C"; done < otherfile > file
. Ou mieux encore, ils auraient dû utiliser le bon outil pour le travail, awk, comme suggéré par Peter . En passant-r
read
, vous voulez presque toujours utiliser le commutateur avec .Réponses:
Il y avait:> dans une ligne d'un script bash. Qu'est-ce que ça veut dire?
C'est un moyen court de dire:
file
n'existe pas, créez-le, sinon tronquez-le en0
octets.Cela signifie que vous pouvez être sûr qu'il
file
existe et qu'il est vide.Vous pouvez également utiliser
> file
mais:> file
est plus portable.Voir la question relative au débordement de pile. Quel est le but de la commande intégrée:: (deux points) GNU Bash? pour plus d'informations.
la source
otherfile
etecho
les diffusefile
. Il crée également des variables à partir de ce qu'il lit. Si vous souhaitez une réponse définitive, posez votre propre question.read
reçoit les entrées de stdin. Seul, il lirait ce que vous tapez. Puisque stdin a été redirigé vers,<otherfile
le contenu deotherfile
"est saisi" dans stdin. Donc,read
obtient les valeurs ligne par ligne dans les variables $ A, $ B, $ C, $ D et $ E.truncate
partir de coreutils?Cela ressemble à une manière élégante de créer un nouveau fichier. In
bash
:
est une commande nulle:>
redirige la sortie de:
vers un fichier.la source
>
fait:
est un raccourci pourtrue
. Peut-être dans certains coquillages,true
un incorporé? Les deux sont intégrés à bash.:
est un autre nom pourtrue
. Les deux sont des commandes shell dans bash, mais non/bin/:
, seulement un/bin/true
. La redirection de sortie entraîne le shell dansopen(2)
le fichier avecO_CREAT|O_TRUNC
. Si rien n'est écrit, il reste à la longueur zéro.Assembler ces deux éléments
:> file
est un idiome assez courant pour tronquer des fichiers. La plupart des gens essaient cependant de rendre cela moins étrange en écrivant: >file
.Comme vous avez demandé dans un commentaire sur la deuxième ligne, je vais transformer mes commentaires en réponse. (même si vous ne l'avez pas demandé dans votre question.)
La deuxième ligne est une boucle qui lit les lignes
otherfile
dans certaines variables nommées. Le corps de la boucle les utiliseecho
pour les imprimer avec des;
séparateurs au lieu des espaces qu’ils avaient auparavant.file
est fermé et rouvert (pour ajouter) chaque itération, car la redirection est à l'intérieur de la boucle. L'utilisationwhile ...;do read -r ...;done <otherfile >file
serait moins efficace, et éviterait de tronquer le fichier en premier.read -r
ne mange pas\
comme un personnage d'évasion.Le traitement du texte à bash est assez lent. Une partie de cela est inévitable:
read
doit aller un octet à la fois (unread(2)
appel système par octet) pour éviter de dépasser la fin d'une ligne. Il serait préférable d'utiliser le bon outil pour le travail:--
signifie que votre script ne casse pas siotherfile
on lui donne un nom idiot--version
.Définir le séparateur de champ de sortie sur
;
signifie que vous pouvez simplement transmettre plusieurs champs en tant qu'arguments à imprimer. Shellread
attribue le reste de la ligne avec les espaces à la dernière variable, mais il n’ya aucun moyen de dire à awk de se scinder uniquement en 5. Si cela est important, continuez simplement à utiliser une boucle bash, car c’est gênant dans awk. Perl facilite cela, car ilsplit
peut prendre beaucoup d'arguments, mais il est beaucoup plus lent à démarrer que awk.En fait, ce n’était pas si difficile, c’était juste une regex laide à écrire. Pour obtenir le reste de la ligne au lieu d'
$5
awk, le bouclage sur les champs perd leur espace d'origine. Ma première idée viable est d'utilisergensub
sur$0
(toute la ligne) pour supprimer les 4 premiers champs (c'est-à-dire les non-espaces suivis par des espaces), en laissant tout le reste:J'ai eu raison dès le premier essai, mais le fait d'être impressionné par moi en dit long sur la lisibilité de ce code awk. >. <
Notez comme c'est le même
print
qu'auparavant, maistail
à la place de$5
.Ce serait plus impressionnant si je pouvais copier / coller le littéral et montrer que cela venait dans la sortie. Tapez un en bash avec ^ Q. ctrl-Q signifie Citer la touche suivante en tant que caractère littéral, car l'édition des lignes de style emacs de bash est identique à celle d'emacs.
http://mywiki.wooledge.org/BashFAQ contient des informations utiles sur les scripts d'une manière qui ne casse pas les données ou les noms de fichiers que vous envoyez au script.
la source