Je connais bien l'utilitaire source
(ou .
), qui extrait le contenu d'un fichier et l'exécute dans le shell en cours.
Maintenant, je transforme du texte en commandes Shell, puis je les exécute comme suit:
$ ls | sed ... | sh
ls
est juste un exemple aléatoire, le texte original peut être n'importe quoi. sed
aussi, juste un exemple pour transformer du texte. Le bit intéressant est sh
. J'écoute tout ce que j'ai à sh
et le lance.
Mon problème est que cela signifie démarrer un nouveau sous-shell. Je préférerais que les commandes soient exécutées dans mon shell actuel. Comme je pourrais le faire avec source some-file
, si j'avais les commandes dans un fichier texte.
Je ne veux pas créer de fichier temporaire car je me sens sale.
Sinon, j'aimerais démarrer mon sous-shell avec exactement les mêmes caractéristiques que mon shell actuel.
Ok, les solutions utilisant backtick fonctionnent, certes, mais je dois souvent le faire pendant que je vérifie et modifie la sortie, alors je préférerais de loin s'il y avait un moyen d'intégrer le résultat dans quelque chose à la fin.
Ah, le /dev/stdin
était si joli, mais dans un cas plus complexe, ça ne marchait pas.
Donc, j'ai ceci:
find . -type f -iname '*.doc' | ack -v '\.doc$' | Perl -pe 's/^((.*)\.doc)$/git mv -f $1 $2.doc/i' | source /dev/stdin
Ce qui garantit que tous les fichiers .doc
ont leur extension en minuscule.
Et qui accessoirement, peut être manipulé avec xargs
, mais c’est d’autre chose.
find . -type f -iname '*.doc' | ack -v '\.doc$' | Perl -pe 's/^((.*)\.doc)$/$1 $2.doc/i' | xargs -L1 git mv
Donc, quand je lance l'ancien, il va sortir tout de suite, rien ne se passe.
$ ls | sed ... | source /dev/stdin
UPDATE: Ceci fonctionne dans bash 4.0, ainsi que tcsh et dash (si vous changez source
en .
). Apparemment, c'était buggy en bash 3.2. Notes de publication de bash 4.0 :
Correction d'un bug qui causait `. ' ne pas lire ni exécuter des commandes à partir de fichiers non normaux tels que des périphériques ou des canaux nommés.
La commande eval
existe à cet effet même.
eval "$( ls | sed... )"
Plus du manuel bash :
eval
eval [arguments]
Les arguments sont concaténés ensemble en une seule commande, qui est ensuite lu et exécuté, et son état de sortie renvoyé comme sortie statut de eval. S'il n'y en a pas arguments ou uniquement des arguments vides, le le statut de retour est zéro.
Wow, je sais que c'est une vieille question, mais je me suis retrouvé exactement avec le même problème récemment (c'est comme ça que je suis arrivé ici).
Quoi qu'il en soit - je n'aime pas la réponse source /dev/stdin
, mais je pense en avoir trouvé une meilleure. C'est faussement simple en fait:
echo ls -la | xargs xargs
Bonne droite? En fait, cela ne fait toujours pas ce que vous voulez, car si vous avez plusieurs lignes, il les concatémera en une seule commande au lieu d'exécuter chaque commande séparément. La solution que j'ai trouvée est donc:
ls | ... | xargs -L 1 xargs
l'option -L 1
signifie que vous utilisez (au plus) 1 ligne par exécution de commande. Remarque: si votre ligne se termine par un espace de fin, elle sera concaténée avec la ligne suivante! Assurez-vous donc que chaque ligne se termine par un non-espace.
Enfin, vous pouvez faire
ls | ... | xargs -L 1 xargs -t
pour voir quelles commandes sont exécutées (-t est détaillé).
J'espère que quelqu'un lit ceci!
Essayez d’utiliser process substitution , qui remplace la sortie d’une commande par un fichier temporaire pouvant ensuite être obtenu:
source <(echo id)
Je crois que c'est "la bonne réponse" à la question:
ls | sed ... | while read line; do $line; done
C'est-à-dire que l'on peut accéder à une boucle while
; la commande read
prend une ligne à partir de sa stdin
et l'assigne à la variable $line
. $line
devient alors la commande exécutée dans la boucle; et il continue jusqu'à ce qu'il n'y ait plus de lignes dans son entrée.
Cela ne fonctionne toujours pas avec certaines structures de contrôle (comme une autre boucle), mais cela convient dans ce cas.
`ls | sed ...`
J'ai le sentiment que ls | sed ... | source -
serait plus joli, mais malheureusement source
ne comprend pas -
qui signifie stdin
.
Je pense que votre solution consiste à remplacer les commandes par des backticks: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html
Voir section 3.4.5
Pour utiliser la solution de mark4o sur bash 3.2 (macos), une chaîne here peut être utilisée à la place de pipelines, comme dans cet exemple:
. /dev/stdin <<< "$(grep '^alias' ~/.profile)"
Pourquoi ne pas utiliser source
alors?
$ ls | sed ... > out.sh ; source out.sh