How do I diff files/folders across machines provided that the only connectivity available is ssh?
16 Answers
You can do it with Bash's process substitution:
diff foo <(ssh myServer 'cat foo')
or the same with
ssh myServer cat foo | diff foo -
Or, if both are on remote servers:
diff <(ssh myServer1 'cat foo') <(ssh myServer2 'cat foo')
-
17
-
How do you mean for directories, could always replace cat with ls Aug 26, 2009 at 17:29
-
32
-
10I found that this technique didn't work for me if my remote host required a password. The password prompt didn't seem to work well with the redirection and couldn't be successfully completed. If you use ssh keys this shouldn't be a problem. Jan 24, 2012 at 14:28
-
2This is a great general solution to many problems. Instead of 'cat foo' you could use 'find /foo/bar -type f | while read file; do echo "**** $file"; cat "$file"; done' and you'd have a list of the file names and file contents to diff. Nov 11, 2014 at 22:22
Finally I've found great solution: vimdiff
vimdiff /path/to/file scp://remotehost//path/to/file
thanks to http://linux.spiney.org/remote_diff_with_vim_and_ssh see also http://www.vim.org/scripts/script.php?script_id=1075 .
-
13
-
1Here is an example: vimdiff .bash_profile scp://[email protected]//home/vaibhavc/.bash_profile Feb 19, 2014 at 22:56
-
62 slashes
//
after theremotehost
is important. Single slash will not work Apr 7, 2014 at 2:05 -
3If you have a different username on the remote host than your current host, you would use
vimdiff /path/to/file scp://username@remotehost//path/to/file
– JaredCMay 19, 2014 at 15:21 -
how can you do this with two remote hosts with id_rsa key files @JaredC?– ManataxMar 12, 2015 at 18:01
If you just want to see what files are different, rather than a diff of the actual files, then you can use rsync --dry-run
-
13
-
Great - if you need to use another port, use rsync -e "ssh -p 2222" <SRC> <DST>– SamothJul 12, 2015 at 6:22
-
1This just lists all files unless you use additional flags ( see serverfault.com/a/591988/125286 ). Nov 15, 2021 at 12:16
Here's another quick and dirty command line recipe. Unlike the chosen answer, it works inside of makefiles:
ssh [login]@[host] "cat [remote file]" | diff - "[local file]"
-
@Steve Dickinson - what do you mean by "it works inside of makefiles" ? May 25, 2014 at 13:43
-
1This is also a nice solution if you're suffering from vim allergy like myself. :) I created a bash script that compares the same file on two different hosts, useful when migrating services between machines and comparing config files. See gist.github.com/jhqv/dbd59f5838ae8c83f736bfe951bd80ff– JanekOct 14, 2016 at 9:09
-
Use scp to bring the files to a common machine and diff them there?
Or, if you just want to know if the files are different or not, hash them with md5sum on each machine.
You could also look into something like SSHFS, but I don't know how well an algorithm like diff performs over that.
-
2An easier way to see if the files are different or not is
rsync --dry-run
. Aug 26, 2009 at 20:18 -
One way, if it is possible on your system would be to simply mount the remote filesystem with sshfs.
-
1diff is usually one-shot action, like to check config difference. Mounting filesystem each time is possible, but not convinient. I'd better tar and scp. Aug 26, 2009 at 17:28
You can use rsync
in dry run mode, as suggested briefly in another answer. It lists any files that are different.
For that, use the rvnc
options (r
=recursive, v
=verbose, n
= dry-run, c
=checksum). With rsync
in pull mode (rsync [OPTION...] [USER@]HOST:SRC... [DEST]
), an example is:
rsync -rvnc [email protected]:/var/www/html/dev/ .
Remember, this provides no info on whether the local or remote file is newer. Just if they differ.
-
1
If you have sshfs and need to diff directories:
mkdir remote_path
sshfs user@host:/path/ remote_path
diff -r path remote_path
on your local machine, make a recursive copy of the directory you want to diff. For instance:
cp -R dir replica
use rsync to replicate the remote directory over the local copy:
rsync remote:/path/to/dir replica
use diff to find difference between the local directory and the local replica of the remote one:
diff dir replica
This is a script that can help to diff local folder and remote folder.:
#!/bin/bash
LOCALFOLDER=/var/www/tee
REMOTEFOLDER=$(ssh [email protected] 'ls -lA /hfs/tee'| grep -E '^total' | cut -d " " -f 2 > remotessh.txt)
COMMAND=$(ls -lA $LOCALFOLDER | grep -E '^total' | cut -d " " -f 2 > localssh.txt)
REM=$(cat remotessh.txt)
LOCAL=$(cat localssh.txt)
echo $LOCAL
echo $REM
if [ $REM -eq $LOCAL ]
then
echo Directories are the same
else
echo Directories are differnt
fi
#diff localssh.txt remotessh.txt | grep -E '^total' | cut -d " " -f 2
Use sshfs mounted across ssh. It won't be all that fast, but you can use your full suite of tools that expect everything to be on a local filesystem. An alternative is NFS over a tunnel made with "ssh -w" (or other communications where ssh isn't the limitation).
http://myfedora.co.za/2012/04/diff-two-remote-file-systems/
diff <(/usr/bin/ssh [email protected] 'ls /opt/lib/') <(/usr/bin/ssh [email protected] 'ls /tmp/') | grep -i ">" | sed 's/> //g'
Here is how I did it.
I used SFTP to the remote server and entered my username/pwd when prompted.
Then I used the dir that was created in the .gvfs
dir in my home directory in the diff command.
diff -r --brief /home/user dir/.gvfs/SFTP\ on\ freenas.local/path to dir/dir1 /path to local dir/dir2
You could also try generalizing the approach by creating a bash function, possibly in your ~/.bashrc
:
myrdiff() { ssh root@"$1" cat "$2" | diff -s - "$2" ; }
then invoking it with a construct like:
myrdiff vm20-x86-64 /etc/gdm/Init/Default
By invoking diff with -s
, this will also report if the files are identical.
using grep
remote ip: 172.16.98.130
remote file: /etc/ssh/keys-root/authorized_keys
local file: ~/.ssh/id_rsa.pub
Now compare the contents of remote file with the local file using grep
grep -w "$(cat ~/.ssh/id_rsa.pub)" <<< $(sshpass -p "mypassword" ssh [email protected] 'cat /etc/ssh/keys-root/authorized_keys')
check the success status of the grep command
echo $?
# 0
Using this idea to setup SSH passwordless login:
if ! grep "$(cat ~/.ssh/id_rsa.pub)" <<< $(sshpass -p "mypassword" ssh [email protected] cat /etc/ssh/keys-root/authorized_keys) &>/dev/null; then
cat ~/.ssh/id_rsa.pub | sshpass -p "mypassword" ssh [email protected] "cat >> /etc/ssh/keys-root/authorized_keys"
fi
ssh [email protected]
Note:
Make sure sshpass
package is installed for passing password non-interactively to ssh
command.
-
sshpass leave an unencripted password in your logs. I wouldn't use this in production. Set up SSH keys for logins. Mar 9, 2020 at 15:24
I use | cat
at the end of the command for interactive password prompts and sdiff
because it is easier to read than diff
:
So between local and remote, type :
sdiff -s cat myfile<(ssh server1 'cat myfile') | cat
and between two servers, type :
sdiff -s <(ssh server1 'cat myfile') <(ssh server2 'cat myfile') | cat
rsync -ani --delete / root@remotehost:/
but the full answer gives more detail.