По какой-то причине (это случилось до того, как я начал работать над этим проектом) - на веб-сайте моего клиента есть 2 дубликата каждого файла. Фактически утроение размера сайта.
Файлы выглядят примерно так:
wp-comments-post.php | 3,982 bytes
wp-comments-post (john smith's conflicted copy 2012-01-12).php | 3,982 bytes
wp-comments-post (JohnSmith's conflicted copy 2012-01-14).php | 3,982 bytes
Хостинг, на котором находится веб-сайт, не имеет доступа к bash или SSH.
Как вы считаете, как проще всего удалить эти повторяющиеся файлы, что займет меньше всего времени?
Я написал сценарий поиска дубликатов в PowerShell, используя Сборка WinSCP .NET.
Актуальная и улучшенная версия этого скрипта теперь доступна как расширение WinSCP.
Найдите дубликаты файлов на SFTP / FTP сервере.
Сценарий сначала выполняет итерацию по дереву удаленных каталогов и ищет файлы того же размера. Когда он их обнаруживает, он по умолчанию загружает файлы и сравнивает их локально.
Если вы знаете, что сервер поддерживает расширение протокола для расчета контрольных сумм, вы можете повысить эффективность скрипта, добавив -remoteChecksumAlg
переключатель, чтобы сценарий запрашивал у сервера контрольную сумму, сохраняя загрузку файла.
powershell.exe -File find_duplicates.ps1 -sessionUrl ftp://user:password@example.com/ -remotePath /path
Сценарий такой:
param (
# Use Generate URL function to obtain a value for -sessionUrl parameter.
$sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xxxxxxxxx...=@example.com/",
[Parameter(Mandatory)]
$remotePath,
$remoteChecksumAlg = $Null
)
function FileChecksum ($remotePath)
{
if (!($checksums.ContainsKey($remotePath)))
{
if ($remoteChecksumAlg -eq $Null)
{
Write-Host "Downloading file $remotePath..."
# Download file
$localPath = [System.IO.Path]::GetTempFileName()
$transferResult = $session.GetFiles($remotePath, $localPath)
if ($transferResult.IsSuccess)
{
$stream = [System.IO.File]::OpenRead($localPath)
$checksum = [BitConverter]::ToString($sha1.ComputeHash($stream))
$stream.Dispose()
Write-Host "Downloaded file $remotePath checksum is $checksum"
Remove-Item $localPath
}
else
{
Write-Host ("Error downloading file ${remotePath}: " +
$transferResult.Failures[0])
$checksum = $False
}
}
else
{
Write-Host "Request checksum for file $remotePath..."
$buf = $session.CalculateFileChecksum($remoteChecksumAlg, $remotePath)
$checksum = [BitConverter]::ToString($buf)
Write-Host "File $remotePath checksum is $checksum"
}
$checksums[$remotePath] = $checksum
}
return $checksums[$remotePath]
}
function FindDuplicatesInDirectory ($remotePath)
{
Write-Host "Finding duplicates in directory $remotePath ..."
try
{
$directoryInfo = $session.ListDirectory($remotePath)
foreach ($fileInfo in $directoryInfo.Files)
{
$remoteFilePath = ($remotePath + "/" + $fileInfo.Name)
if ($fileInfo.IsDirectory)
{
# Skip references to current and parent directories
if (($fileInfo.Name -ne ".") -and
($fileInfo.Name -ne ".."))
{
# Recurse into subdirectories
FindDuplicatesInDirectory $remoteFilePath
}
}
else
{
Write-Host ("Found file $($fileInfo.FullName) " +
"with size $($fileInfo.Length)")
if ($sizes.ContainsKey($fileInfo.Length))
{
$checksum = FileChecksum($remoteFilePath)
foreach ($otherFilePath in $sizes[$fileInfo.Length])
{
$otherChecksum = FileChecksum($otherFilePath)
if ($checksum -eq $otherChecksum)
{
Write-Host ("Checksums of files $remoteFilePath and " +
"$otherFilePath are identical")
$duplicates[$remoteFilePath] = $otherFilePath
}
}
}
else
{
$sizes[$fileInfo.Length] = @()
}
$sizes[$fileInfo.Length] += $remoteFilePath
}
}
}
catch [Exception]
{
Write-Host "Error processing directory ${remotePath}: $($_.Exception.Message)"
}
}
try
{
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"
# Setup session options from URL
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.ParseUrl($sessionUrl)
$session = New-Object WinSCP.Session
$session.SessionLogPath = "session.log"
try
{
# Connect
$session.Open($sessionOptions)
$sizes = @{}
$checksums = @{}
$duplicates = @{}
$sha1 = [System.Security.Cryptography.SHA1]::Create()
# Start recursion
FindDuplicatesInDirectory $remotePath
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
# Print results
Write-Host
if ($duplicates.Count -gt 0)
{
Write-Host "Duplicates found:"
foreach ($path1 in $duplicates.Keys)
{
Write-Host "$path1 <=> $($duplicates[$path1])"
}
}
else
{
Write-Host "No duplicates found."
}
exit 0
}
catch [Exception]
{
Write-Host "Error: $($_.Exception.Message)"
exit 1
}
(Я автор WinSCP)
Изменить: используйте ftpfs для монтирования удаленной файловой системы ftp в локальной точке монтирования, затем используйте любой другой подход, описанный здесь.
Если все файлы соответствуют этому синтаксису, вы можете, например,
rbos@chili:~/tmp$ touch asdf.php
rbos@chili:~/tmp$ touch "asdf (blah blah blah).php"
rbos@chili:~/tmp$ touch "asdf (blah blah rawr).php"
rbos@chili:~/tmp$ find | grep "(.*)"
./asdf (blah blah rawr).php
./asdf (blah blah blah).php
чтобы сопоставить файлы, а затем просто передайте это в xargs или цикл для проверки списка:
find | grep "(.*)" | while read i; do echo "$i";done | less
а затем заменить echo
с участием rm
как только вы убедитесь, что список точен.
Ты можешь использовать FSlint чтобы найти повторяющиеся файлы.
FTP на сервер и rm
файлы.
Запустите это: find /yourdir -name "*conflicted copy*" -type f -ls
Если перечисленные файлы - это те, которые вы хотите удалить, измените -ls
для -delete
и снова запустите.
Я предлагаю сначала сделать резервную копию вашего базового каталога с помощью tar, прежде чем вы это сделаете ...
РЕДАКТИРОВАТЬ: Я только что понял, что у вас нет доступа к сеансу оболочки, поэтому это не сработает для вас ...
Вероятно, вам понадобится что-то вроде этого: http://www.go4expert.com/forums/showthread.php?t=2348 чтобы рекурсивно выгрузить список файлов, а затем создать другой сценарий, который удаляет только те, которые вам нужны.