: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:
awk -vOFS=';' '{ print $1, $2, $4, $5, $3 }' -- otherfile >file
--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:
awk -vOFS=';' '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1); print $1, $2, $4, tail, $3 }' -- otherfile >file
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.