Ramblings of General Geekery

Poor man’s search engines sync for Google Chrome

Update: since Lifehacker featured this post on their home page, I released some simpler updated version of the scripts here.

The wonderful thing about open-source software is that whenever something’s missing, anybody can go ahead and fix it… that is, unless nobody cares enough about it. And that’s precisely what’s happening with the “search engines sync” feature in Google Chrome, which has been in Chromium’s bug database for more than a year and a half. Looks like Google is not so much in a hurry to let you use other search engines as soon as you install a fresh copy of their browser.

Oh, don’t look at me. I seriously don’t have the time to dive into such a big codebase to add the feature myself… but what I do have the time for is a little scripted hack to get around the problem quickly!

Google Chrome, like a lot of programs these days, is using SQLite to store its data. Your search engines are stored in a database called “Web Data”, in a table called “keywords”. It’s quite easy to use the SQLite command line shell to export and import that table across your computers… so that’s what I did. There are 2 scripts: one to export, and one to import, although I called them “push” and “pull” to sound cool like the Git/Mercurial guys.

Windows

On Windows, my scripts are written in Powershell, which ships by default with Windows 7. On previous versions of Windows, Powershell ships with some service packs, so if you’re up to date you should have it. Otherwise, go get it from Microsoft’s website.

Update: if you’ve never run any Powershell script before, you’ll have to change the security settings because I didn’t sign my scripts. Run Powershell as an administrator and type “Set-ExecutionPolicy RemoteSigned”.

You’ll need to also download the SQLite command line shell (no install required, it’s just one .exe file in a zip). Just keep it next to the script files.

Here’s the export script:

param (
    [String] $Destination = "keywords.sql"
)

$CurrentDir = Split-Path -Parent $MyInvocation.MyCommand.Path
if (![IO.Path]::IsPathRooted($Destination)) { $Destination = [IO.Path]::Combine($CurrentDir, $Destination) }
$Destination = $Destination.Replace('', '/')
$TempSqlScript = "$env:TEMPsync_chrome_sql_script"

Push-Location
Write-Output "Exporting Chrome keywords to $Destination..."
cd "$HOMEAppDataLocalGoogleChromeUser DataDefault"
Write-Output ".output `"$Destination`"" | Out-File $TempSqlScript -Encoding ASCII
Write-Output ".dump keywords" | Out-File $TempSqlScript -Encoding ASCII -Append
& "$CurrentDirsqlite3.exe" -init $TempSqlScript "Web Data" .exit
Remove-Item $TempSqlScript
Pop-Location

And here’s the import script:

param (
    [String] $Source = "keywords.sql"
)

if ((Get-Process -Name chrome -ErrorAction SilentlyContinue | Measure-Object).Count -gt 0)
{
    throw "Close Chrome and try again..."
}

$Reply = Read-Host -Prompt "This will overwrite your Google Chrome search engines! Are you sure?  "
if (!($Reply -match "^(Y|y|YES|Yes|yes)$"))
{
    Write-Output "Cancelling operation."
    exit
}

$CurrentDir = Split-Path -Parent $MyInvocation.MyCommand.Path
if (![IO.Path]::IsPathRooted($Source)) { $Source = [IO.Path]::Combine($CurrentDir, $Source) }
$Source = $Source.Replace('', '/')
$TempSqlScript = "$env:TEMPsync_chrome_sql_script"

Push-Location
Write-Output "Importing Chrome keywords from $Source..."
cd "$HOMEAppDataLocalGoogleChromeUser DataDefault"
Write-Output "DROP TABLE IF EXISTS keywords;" | Out-File $TempSqlScript -Encoding ASCII
Write-Output ".read `"$Source`"" | Out-File $TempSqlScript -Encoding ASCII -Append
& "$CurrentDirsqlite3.exe" -init $TempSqlScript "Web Data" .exit
Remove-Item $TempSqlScript
Pop-Location

MacOS X

On MacOS X I’m using bash so all you need is to make sure you’ve got the SQLite command line shell. You can either download it directly, or use one of the package managers like MacPorts or Homebrew (I’m using the latter myself).

Here’s the export script:

#!/bin/sh

DESTINATION=${1:-./keywords.sql}
TEMP_SQL_SCRIPT=/tmp/sync_chrome_sql_script
echo "Exporting Chrome keywords to $DESTINATION..."
cd ~/Library/Application Support/Google/Chrome/Default
echo .output $DESTINATION > $TEMP_SQL_SCRIPT
echo .dump keywords >> $TEMP_SQL_SCRIPT
sqlite3 -init $TEMP_SQL_SCRIPT Web Data .exit
rm $TEMP_SQL_SCRIPT

And here’s the import script:

#!/bin/sh
if ps -x | grep -v grep | grep Google Chrome > /dev/null; then
    echo "Close Chrome and try again..."
    exit 1
fi

read -p "This will overwrite your Google Chrome search engines! Are you sure?  " -n 1
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    echo "Cancelling operation."
    exit 1
fi

SOURCE=${1:-./keywords.sql}
TEMP_SQL_SCRIPT=/tmp/sync_chrome_sql_script
echo
echo "Importing Chrome keywords from $SOURCE..."
cd ~/Library/Application Support/Google/Chrome/Default
echo DROP TABLE IF EXISTS keywords; > $TEMP_SQL_SCRIPT
echo .read $SOURCE >> $TEMP_SQL_SCRIPT
sqlite3 -init $TEMP_SQL_SCRIPT Web Data .exit
rm $TEMP_SQL_SCRIPT

Bringing it all together with Dropbox

Those scripts handle importing and exporting our search engines, but we’re missing the “sync” part so far. That’s where popular syncing service Dropbox comes into play (but you can do this with any other syncing service). Just put all this stuff (the SQLite command line shell, the scripts, and the database dump) in a Dropbox folder. All you have to do is run the “export/push” script after you’ve changed your search engines, and run the “import/pull” script next time you get on another computer. Dropbox will have synced the dumped database file (“keywords.sql” by default) in the meantime (unless you’re moving really super fast, in which case you’ll have to wait a second or two).

I’ve made a handy ZIP file with those scripts, a couple of bootstrap (double-clickeable) files for Windows, and the SQLite win32 command line shell. So download it and start syncing in a very hacky and lame way!