Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

When I want to compare a local file with a remote file, any of these usually works:

$ ssh remote cat file | diff file -
$ diff file <(ssh remote cat file)

However, sometimes (especially when the password is needed) they fail like this:

$ ssh remote cat file | diff file -
1,162d0
< ...
< ...
Password: 

Here, diff doesn't wait for ssh to complete and considers the second file empty. It is only after diff is finished that ssh asks for the password, but it is too late.

$ diff file <(ssh remote cat file)
Password: 
Password:       # asking again after a few seconds
#&%Pasword:     # the typed raw password leaks into the terminal
user@remote's password:
Permission denied, please try again.
user@remote's password:
Permission denied, please try again.
user@remote's password:
Received disconnect from XXX.XX.XX.XX: 2: Too many authentication failures for user
1,162d0
< ...
< ...

This time, ssh asks for the password, but the typed password is echoed back to the terminal, and ssh doesn't get it. Finally, ssh fails and diff continues with an empty second file.

Can you explain why these are happening, or what's happening in detail under the hood?

share|improve this question
1  
I can't explain or reproduce this behavior. What OS are you running, what shell, what version? If you move your ~/.bashrc, ~/.zshrc or other relevant file out of the way, does it make a difference? P.S. Mount the remote directory with SSHFS, then call diff on the two regular files. –  Gilles Jul 27 '12 at 0:50
    
Ubuntu 12.04, bash 4.2.24(1)-release. –  musiphil Jul 27 '12 at 5:52
    
It seems that alias diff='colordiff' messed up with the redirection; not using the alias solves the problem for the pipeline case. Thank you! However, the process substitution case remains the same. Even cat <(ssh remote cat file) fails in the same way. –  musiphil Jul 27 '12 at 6:02

1 Answer 1

up vote 2 down vote accepted

When you run ssh first:

ssh remote 'cat file' | cat

ssh gets your controlling terminal as stdin, so you can type your password in with no problems.

When you use bash's process substitution, stdin remains connected to the first command, and the subprocess's output pipe gets passed to the first command as an argument:

cat <(ssh remote 'cat file')

If the ssh negotiation succeeded, /dev/fd/63 will be a pipe containing the output of ssh remote 'cat file'.

This can be demonstrated with the following command:

$ echo <(ls)
/dev/fd/63

The important part of this is that your terminal is connected to cat's stdin, not ssh's. When this runs, cat gets a command-line argument like /dev/fd/63. Therefore, cat ignores stdin altogether; however, it is still connected to the cat process, and not ssh, so your password goes nowhere.

If you want to change this, you will need to run ssh first, and pipe the output to diff, as you have already demonstrated above:

ssh remote 'cat file' | diff file -
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.