web-dev-qa-db-fra.com

Comment composer des fonctions Bash à l'aide de tuyaux?

J'ai peu de fonctions définies dans cette mode:

function f {
  read and process $1
  ...
  echo $result
}

Je veux les composer ensemble pour que l'invocation ressemblerait à f | g | h.

Quel idiome devais-je utiliser pour convertir la fonction travaillant sur des arguments en arguments de lecture de stdin? Est-il possible de lire des paires, des tunples d'arguments à partir de flux sans avoir besoin de leur échapper (par exemple, terminade null)?

18
Rumca

Une approche potentielle serait de mettre un while...read Construisez-vous à l'intérieur de vos fonctions qui traiterait toutes les données entrées dans la fonction via STDIN, utilisez-la, puis émettez les données résultantes en arrière via Stdout.

function X {
  while read data; do
    ...process...
  done
}

Les soins devront être dépensés avec la manière dont vous configurez votre while ..read.. Composants car ils dépendent fortement des types de données qu'ils seront en mesure de consommer de manière fiable. Il peut y avoir une configuration optimale que vous pouvez trouver.

Exemple

$ logF() { while read data; do echo "[F:$(date +"%D %T")] $data"; done; }
$ logG() { while read data; do echo "G:$data";                    done; }
$ logH() { while read data; do echo "H:$data";                    done; }

Voici chaque fonction par lui-même.

$ echo "hi" | logF
[F:02/07/14 20:01:11] hi

$ echo "hi" | logG
G:hi

$ echo "hi" | logH
H:hi

Ici, ils sont quand nous les utilisons ensemble.

$ echo "hi" | logF | logG | logH
H:G:[F:02/07/14 19:58:18] hi

$ echo -e "hi\nbye" | logF | logG | logH
H:G:[F:02/07/14 19:58:22] hi
H:G:[F:02/07/14 19:58:22] bye

Ils peuvent prendre différents styles d'entrée.

#-- ex. #1
$ cat <<<"some string of nonsense" | logF | logG | logH
H:G:[F:02/07/14 20:03:47] some string of nonsense

#-- ex. #2    
$ (logF | logG | logH) <<<"Here comes another string."
H:G:[F:02/07/14 20:04:46] Here comes another string.

#-- ex. #3
$ (logF | logG | logH)
Look I can even
H:G:[F:02/07/14 20:05:19] Look I can even
type to it
H:G:[F:02/07/14 20:05:23] type to it
live
H:G:[F:02/07/14 20:05:25] live
via STDIN
H:G:[F:02/07/14 20:05:29] via STDIN
..type Ctrl + D to stop..

#-- ex. #4
$ seq 5 | logF | logG | logH
H:G:[F:02/07/14 20:07:40] 1
H:G:[F:02/07/14 20:07:40] 2
H:G:[F:02/07/14 20:07:40] 3
H:G:[F:02/07/14 20:07:40] 4
H:G:[F:02/07/14 20:07:40] 5

#-- ex. #5
$ (logF | logG | logH) < <(seq 2)
H:G:[F:02/07/14 20:15:17] 1
H:G:[F:02/07/14 20:15:17] 2
21
slm

En tant qu'addendum à SLM Réponse, j'ai fait des expériences avec des tuples séparés par NULL comme arguments de la fonction:

$ sayTuple() { 
    IFS= read -r -d $'\0' d1
    IFS= read -r -d $'\0' d2
    echo "sayTuple: -$d1- -$d2-"
}

Remarques: sayTuple lit deux fois un enregistrement null terminé -d $'\0' Manipulation de tout espace entourant l'entrée IFS=. echo _ enregistrements arrière entourés de -

Le résultat montre qu'il gère correctement une entrée null terminée contenant \n et \t:

$ printf "%s\0%s\0" "Hello " $' Brave\n\tWorld' | sayTuple 
sayTuple: -Hello - - Brave
        World-

Veuillez ajouter des suggestions d'amélioration des commentaires, c'est un sujet intéressant.

4
grebneke