Comment exécuter une commande à distance et passer en fichier local en entrée?

22

Est-il possible de faire cela:

ssh user@socket command /path/to/file/on/local/machine

C'est-à-dire que je veux exécuter une commande à distance en utilisant un fichier local en une seule étape, sans d'abord utiliser scppour copier le fichier.

jsj
la source
C'est possible si l'ordinateur distant a un montage réseau d'un répertoire parent du fichier de la machine locale ou si vous redirigez le fichier dans la commande ssh
h3rrmiller

Réponses:

23

Vous avez manqué un seul symbole =)

ssh user@socket command < /path/to/file/on/local/machine
se ruer
la source
Bien sûr! Je me demande pourquoi je n'ai pas envisagé la redirection d'entrée sur ssh?!
jsj
Que faire si la commande à distance ne peut prendre qu'un argument de fichier et ne pas lire depuis stdin?
iruvar
@ChandraRavoori dans ce cas, vous devez le copier avec scpavant.
précipiter
4
@ChandraRavoori Vous pouvez essayer de lui donner l'argument de fichier /dev/stdinou -. Peut ou peut ne pas fonctionner ( /dev/stdinest un fichier, mais sa recherche échouera)
derobert
1
@derobert et rush, ont joué un peu avec et ont découvert un moyen hacky de le faire en utilisant la substitution de processus sous bash. Ceci est toujours soumis à la limitation de recherche et peut devenir lourd avec tous les devis supplémentaires qui seront nécessaires. Un exemple suit. cat test.file | ssh user @ machine 'bash -c "wc -l <(cat -)"'
iruvar
4

Une façon qui fonctionne quelle que soit la commande est de rendre le fichier disponible sur la machine distante via un système de fichiers distant. Puisque vous avez une connexion SSH:

  1. Établissez un tunnel SSH inversé . Voir aussi SSH copier facilement le fichier sur le système local
  2. Montez une arborescence de répertoires de votre machine contenant le fichier à partager sur la machine distante avec SSHFS . ( Exemple )
Gilles 'SO- arrête d'être méchant'
la source
Quoi qu'il en soit, cela nécessite des mouvements supplémentaires avant l'exécution de la commande.
précipiter
@ Gilles: Je pense que le titre original était trompeur, et vous avez compris sa question sur la base du titre trompeur. Autant que je sache, pensait, il ne voulait pas réellement agir sur le fichier local, mais simplement le transmettre en entrée. (Mais votre réponse est incroyable, si je la comprends bien! Je devrais peut-être poser la question à laquelle vous avez répondu, juste pour vous donner un endroit où mettre la réponse où vous obtiendrez le crédit approprié.) J'ai édité le titre des questions pour le rendre cohérent avec le corps et avec la réponse choisie.
iconoclaste du
@iconoclast Je ne me souviens pas de mon état d'esprit quand j'ai écrit ceci, mais je me fie à cette réponse. Il nécessite une certaine configuration mais a l'avantage de généraliser au-delà de l'exigence immédiate dans d'autres cas où il ne suffit pas de copier l'entrée. J'aurais également mentionné la redirection si quelqu'un d'autre ne l'avait pas fait. La question plus générale a été posée à plusieurs reprises sous des formes légèrement différentes.
Gilles 'SO- arrête d'être méchant'
D'accord, je dois avoir mal compris votre réponse. Je ne l'ai pas essayé, mais j'ai déduit que puisque vous établissiez un tunnel inverse (de l'hôte distant à l'hôte local?), Vous autorisiez la modification du fichier local par la machine distante. N'est-ce pas le cas?
iconoclaste du
@iconoclast Oui, cela permet à la machine distante de modifier le fichier local (en plus de lui permettre de le lire, ce que demande la question).
Gilles 'SO- arrête d'être méchant'
1
# What if remote command can only take a file argument and not read from stdin? (1_CR)
ssh user@socket command < /path/to/file/on/local/machine
...
cat test.file | ssh user@machine 'bash -c "wc -l <(cat -)"'  # 1_CR

Comme alternative à la bashsubstitution de processus <(cat -)ou < <(xargs -0 -n 1000 cat)(voir ci-dessous), vous pouvez simplement utiliser xargset catdiriger le contenu des fichiers spécifiés vers wc -l(qui est plus portable).

# Assuming that test.file contains file paths each delimited by an ASCII NUL character \0
# and that we are to count all those lines in all those files (provided by test.file).

#find . -type f -print0 > test.file
# test with repeated line count of ~/.bash_history file
for n in {1..1000}; do printf '%s\000' "${HOME}/.bash_history"; done > test.file

# xargs & cat
ssh localhost 'export LC_ALL=C; xargs -0 -n 1000 cat | wc -l' <test.file

# Bash process substitution
cat test.file | ssh localhost 'bash -c "export LC_ALL=C; wc -l < <(xargs -0 -n 1000 cat)"'
franc
la source