Как мне различить два текстовых файла в Windows Powershell?

96

У меня есть два текстовых файла, и я хочу найти различия между ними с помощью Windows Powershell. Есть ли что-то похожее на инструмент сравнения Unix? Или есть другой способ, который я не рассмотрел?

Я пробовал сравнить объект, но получить этот загадочный вывод:

PS C:\> compare-object one.txt two.txt

InputObject                                                 SideIndicator
-----------                                                 -------------
two.txt                                                     =>
one.txt                                                     <=
Брайан Уиллис
источник

Ответы:

101

Сам разобрался. Поскольку Powershell работает с объектами .net, а не с текстом, вам необходимо использовать get-content для отображения содержимого текстовых файлов. Чтобы выполнить то, что я пытался сделать в этом вопросе, используйте:

compare-object (get-content one.txt) (get-content two.txt)
Брайан Уиллис
источник
1
Я был очень удивлен, когда попытался сравнить два файла: несортированный массив чисел и тот же массив чисел после их сортировки. Нет выходных данных, несмотря на то, что файлы очень разные. Видимо, объект сравнения не учитывает порядок.
cgmb
1
@cgmb - -SyncWindow 0Я думаю, вы можете это исправить, хотя я не уверен, что это только недавно. Это не особенно умно об этом, хотя.
Джеймс Раскин
32

Более простой способ сделать это - написать:

diff (cat file1) (cat file2)
Алекс Й.
источник
16
Diff и cat - это просто псевдонимы для Compare-Object и Get-Content в PowerShell. Это то же самое.
Шон Мелтон
4
несмотря на то, что это совпадает с принятым ответом, мне больше нравится использовать этот синтаксис
Элайджа В. Ганье
Обратите внимание, что он не ведет себя как * nix diffвообще, как отмечают другие ответы здесь. И когда я использовал более сложное выражение вместо, catя получил неправильный вывод, поэтому я присоединюсь к другим в рекомендации, чтобы избежать этого в PowerShell, если вы пришли из * nix.
Николай
29

Или вы можете использовать команду DOS fcследующим образом (здесь показаны выходные данные обоих файлов, поэтому вам придется искать различия):

fc.exe filea.txt fileb.txt > diff.txt

fcпсевдоним командлета Format-Custom, поэтому обязательно введите команду какfc.exe . Обратите внимание, что многие утилиты DOS не поддерживают кодировку UTF-8.

Вы также можете запустить процесс CMD и запустить fcего внутри.

start cmd "/c  ""fc filea.txt fileb.txt >diff.txt"""

Это указывает PowerShell запустить процесс с помощью программы cmd, используя параметры в кавычках. В кавычках есть опция '/ c' cmd для запуска команды и завершения. Фактическая команда, запускаемая cmd в процессе, fc filea.txt fileb.txtперенаправляет вывод в файл diff.txt.

Вы можете использовать DOS fc.exeиз PowerShell.

phord350
источник
2
+1 за вывод DOS ^ _ ^
Джефф Бриджман
1
«fc» не работал для меня, и я не осознавал, что должен был указать его как «fc.exe», чтобы отличить его от Format-Custom. Именно то, что я искал. Благодарю.
Ксонатрон
Может быть, я полный обыватель, но мне это кажется гораздо более полезным. Это очень хорошо решило мою проблему.
AJ.
Единственная проблема - это ненависть к юникоду.
iCodeSometime
7

diff on * nix - это не часть оболочки, а отдельное приложение.

Есть ли причина, по которой вы не можете просто использовать diff.exe под PowerShell?

Вы можете скачать версию из пакета UnxUtils ( http://unxutils.sourceforge.net/ )

Mikeage
источник
10
Поскольку PowerShell включен сейчас, загружать и устанавливать нечего.
Bratch
Я только что закончил использовать git diff, потому что я уже установил его. Ни то, fc.exeни другое не Compare-Objectдало ожидаемого результата.
Разиэль
4

Сравнивать объект (он же diff) является жалким, если вы ожидаете, что он будет вести себя как Unix Diff. Я попробовал diff (gc file1) (gc file2), и если строка слишком длинная, я не вижу фактического diff и, что более важно, я не могу сказать, на каком номере строки находится diff.

Когда я пытаюсь добавить -passthru, я теперь вижу разницу, но я теряю, в каком файле находится разница, и все равно не получаю номер строки.

Мой совет, не используйте PowerShell, чтобы найти различия в файлах. Как кто-то еще заметил, fc работает и работает немного лучше, чем Compare-Object, и еще лучше загружает и использует реальные инструменты, такие как эмулятор Unix, который упоминал Mikeage.

Марк Тауэрсап
источник
По-видимому, он также выполняет сравнение наборов (т.е. игнорирует порядок), как -SyncWindowи maxint по умолчанию. Если установить значение 0, это не будет работать так же, diffкак и ... И когда я передал канал в (... | select-object ...)качестве входных данных, он просто напечатал чепуху, поэтому я сдался.
Николай
3

Как уже отмечали другие, если вы ожидаете вывод unix-y diff, то использование псевдонимов powershell сильно подведет вас. Во-первых, вы должны держать руку на деле при чтении файлов (с помощью gc / get-content). С другой стороны, индикатор разницы справа, вдали от контента - это кошмар читабельности.

Решение для тех, кто ищет вменяемый вывод:

  1. получить реальный diff (например, от GnuWin32)
  2. edit% USERPROFILE% \ Documents \ WindowsPowerShell \ Microsoft.PowerShell_profile.ps1
  3. добавить строку

    remove-item alias:diff -force

Аргумент -force необходим, потому что Powershell весьма ценен в этом конкретном встроенном псевдониме. Если кому-то интересно, установив GnuWin32, я также добавлю следующее в свой профиль powershell:

remove-item alias:rm
remove-item alias:mv
remove-item alias:cp

Главным образом потому, что Powershell не понимает аргументы, которые запускаются вместе и вводят, например, «rm -Force -Recurse» - это гораздо больше усилий, чем «rm -rf».

У Powershell есть несколько приятных функций, но есть некоторые вещи, которые он не должен делать для меня.

ДАФ
источник
2

WinMerge - еще один хороший инструмент сравнения на основе графического интерфейса.

Энди Уайт
источник
1
Это то, как я делал это в прошлом, это ручной процесс, который я хотел заменить небольшим скриптом.
Bratch
1

Есть также Windiff, который предоставляет интерфейс с графическим интерфейсом (отлично подходит для использования с программами CVS / SVN на основе GUI)

saschabeaumont
источник
1

fc.exeлучше для сравнения текста, так как он предназначен для работы подобно * nix diff, то есть сравнивает строки последовательно, показывая реальные различия и пытаясь выполнить повторную синхронизацию (если разные секции имеют разную длину). Он также имеет несколько полезных опций управления (текстовый / двоичный, чувствительность к регистру, номера строк, длина ресинхронизации, размер буфера несоответствия) и обеспечивает состояние выхода (-1 неправильный синтаксис, 0 файлов одинаковы, 1 файл отличается, 2 файла отсутствуют). Будучи (очень) старой утилитой DOS, она имеет несколько ограничений. В частности, он не работает автоматически с Unicode, обрабатывая 0 MSB символов ASCII как терминатор строки, поэтому файл становится последовательностью из 1 строки символов (@kennycoc: используйте параметр / U, чтобы указать, что ОБА файлы являются Unicode, WinXP и далее ) и он также имеет размер буфера жесткой строки 128 символов (128 байтов ASCII,

объект сравнения предназначен для определения того, являются ли 2 объекта идентичными по элементам. если объекты являются коллекциями, то они обрабатываются как SETS (см. справочный объект сравнения), т. е. коллекции UNORDERED без дубликатов. 2 набора равны, если они имеют одинаковые элементы, независимо от порядка или дублирования. Это сильно ограничивает его полезность для сравнения текстовых файлов на предмет различий. Во-первых, поведение по умолчанию собирает различия до тех пор, пока не будет проверен весь объект (файл = массив строк), что приведет к потере информации, касающейся положения различий, и сокрытию различий между парами (и не существует понятия номера строки для SET строк). Использование -synchwindow 0 приведет к тому, что различия будут генерироваться по мере их возникновения, но не будет пытаться выполнить повторную синхронизацию, поэтому, если в одном файле есть лишняя строка, последующие сравнения строк могут завершиться неудачей, даже если файлы в противном случае идентичны (до тех пор, пока не будет получена компенсация). дополнительная строка в другом файле, таким образом выравнивая совпадающие строки). Тем не менее, PowerShell является чрезвычайно универсальным и полезное сравнение файлов может быть сделано с помощью этой функции, хотя и за счет существенной сложности и с некоторыми ограничениями на содержание файлов. Если вам нужно сравнить текстовые файлы с длинными (> 127 символов) строками и где строки в основном совпадают с 1:

diff (gc file1 | % -begin { $ln1=0 } -process { '{0,6}<<:{1}' -f ++$ln1,$_ }) (gc file2 | % -begin { $ln2=0 } -process { '{0,6}>>:{1}' -f ++$ln2,$_ }) -property { $_.substring(9) } -passthru | sort | out-string -width xx

где хх - длина самой длинной строки + 9

объяснение

  • (gc file | % -begin { $ln=0 } -process { '{0,6}<<:{1}' -f ++$ln,$_ }) получает содержимое файла и добавляет номер строки и указатель файла (<< или >>) к каждой строке (используя оператор строки формата) перед передачей его в diff.
  • -property { $_.substring(9) }сообщает diff для сравнения каждой пары объектов (строк), игнорируя первые 9 символов (которые являются номером строки и индикатором файла). При этом используется возможность указать вычисляемое свойство (значение блока скрипта) вместо имени свойства.
  • -passthru заставляет diff выводить разные входные объекты (которые включают номер строки и индикатор файла) вместо отличающихся сравниваемых объектов (которые этого не делают).
  • sort-objectзатем помещает все строки обратно в последовательность.
    out-string останавливает усечение по умолчанию для вывода в соответствии с шириной экрана (как отметил Марк Тауэрсап), указав достаточно большую ширину, чтобы избежать усечения. Обычно этот вывод помещается в файл, который затем просматривается с помощью прокручиваемого редактора (например, блокнота).

Запись

Формат номера строки {0,6} дает выравниваемый справа пробел номер строки из 6 символов (для сортировки). Если файлы имеют более 999 999 строк, просто измените формат на более широкий. Это также требует изменения $_.substringпараметра (на 3 больше ширины номера строки) и внешнего значения xx (максимальная длина строки + $_.substringпараметр).

код-мастер Боб
источник