113

I wanted to be clever and compare a remote file to a local file without first manually downloading it. I can get the contents of the remote file by

ssh user@remote-host "cat path/file.name"

However, piping that to diff

ssh user@remote-host "cat path/file.name" | diff path/file.name

gives me this:

diff: missing operand after `path/file.nae'
diff: Try `diff --help' for more information.

I have ssh keys set up, so it's not prompting me for a password. What's a workaround for this?

iconoclast
  • 9,198
  • 13
  • 57
  • 97
user394
  • 14,404
  • 21
  • 67
  • 93
  • 6
    By the way, you're still downloading the file when you do this (since its content gets sent over the SSH connection), you're just not saving it anywhere. So it's not like you save any bandwidth or anything. – David Z Aug 21 '10 at 00:13
  • 3
    Yeah, I just don't want to muck up my file system with one-shot files hanging around. – user394 Aug 23 '10 at 13:29
  • 2
    for when the command does not support stdin (e.g. via -), you can use /dev/stdin. e.g. diff file1 /dev/stdin – ctrl-alt-delor Mar 15 '17 at 19:46

4 Answers4

135

Use - to represent the standard input:

ssh user@remote-host "cat path/file.name" | diff path/file.name -
Toby Speight
  • 8,678
Hemant
  • 6,910
  • 5
  • 39
  • 42
89

Here's one workaround: diff seems to accept <(expr) as arguemnts:

diff <(ssh \"cat path/file.name/") <(cat path/file.name)
user394
  • 14,404
  • 21
  • 67
  • 93
  • 24
    That's not diff, that's the shell (bash, ksh and zsh support this syntax, but it's not POSIX), with some help from the kernel (it must provide /dev/fd: diff sees something like /dev/fd/3 on its command line). – Gilles 'SO- stop being evil' Aug 20 '10 at 19:25
  • 4
    It doesn't "must provide" - shells can create temporary named pipes for this feature too. – ephemient Sep 24 '10 at 14:11
  • 5
    this is the coolest answer! – neves Dec 20 '11 at 21:47
  • 10
    I personally prefer this answer. I needed to diff two different XML files; but they needed to be properly formed first. That led to this: diff -y <(xmllint --format "${1}") <(xmllint --format "${2}") which I now use all the time. – Niko Oct 08 '14 at 19:49
  • 2
    This is also very useful on OS X where one might want to compare two binary .plist files: diff <(plutil -convert xml1 -o -- "${1}") <(plutil -convert xml1 -o - -- "${2}") – morgant Feb 16 '15 at 18:57
  • 1
    My zsh reports error: /dev/fd/11: unsupported file type fatal: cannot hash /dev/fd/11 but that is because it uses git diff. Running command diff ... instead gives no trouble. – Clemens Tolboom Apr 25 '17 at 06:44
  • This is less portable though. It won't work on all systems. Also, there's no sense in doing <(cat path/file.name) instead of just path/file.name – Zaz Jul 07 '23 at 18:18
3

Piping into diff is equivalent to running

diff path/file.name

and then, once it's running, typing the entire contents of the file.

As you can see, that's not what you expected.

Macha
  • 3,790
1
diff /tmp/localtempfile <(ssh -A -o StrictHostKeyChecking=no root@server "cat /tmp/remotetempfile")
Michael Mrozek
  • 93,103
  • 40
  • 240
  • 233