В BAT-файле сравните файлы по времени модификации: & ldquo; если file1-old-than file2 do & rdquo ;? [dубликат]

Вдохновленный этой подобной записью, которая включает в себя поиск набора бит, я предлагаю следующее:

unsigned GetLowestBitPos(unsigned value) { double d = value ^ (value - !!value); return (((int*)&d)[1]>>20)-1023; }

Плюсы:

нет циклов Нет разветвлений в постоянном времени обрабатывает значение = 0, возвращая результат в противном случае, только две строки кода

Минусы:

no loops предполагает, что double является вещественным * Обновление IEEE 754

. Как отмечено в комментариях, объединение является более чистой реализацией (по крайней мере, для C) и будет выглядеть так:

unsigned GetLowestBitPos(unsigned value) { union { int i[2]; double d; } temp = { .d = value ^ (value - !!value) }; return (temp.i[1] >> 20) - 1023; }

Предполагается, что 32-битные ints с минимально-ориентированным хранилищем для всех (думаю, процессоры x86).

25
задан Dave Webb 6 November 2009 в 13:11
поделиться

5 ответов

Вы можете найти более новый из двух файлов с одной строкой пакетного скрипта. Просто перечислите файлы в порядке дат, самые старые сначала, а это означает, что последним указанным файлом должен быть новый файл. Итак, если вы каждый раз сохраняете имя файла, последнее имя, помещенное в вашу переменную, будет самым новым файлом.

Для примера:

  SET FILE1 = foo.txt  SET FILE2 = bar.txt FOR / F %% i IN ('DIR / B / O: D% FILE1%% FILE2%') DO SET NEWEST = %% i ECHO% NEWEST% (возможно) новее.   

Это, к сожалению, не соответствует тем, что метки дат совпадают. Поэтому нам просто нужно проверить, имеют ли файлы первую и последнюю дату:

  SET FILE1 = foo.txt SET FILE2 = bar.txt FOR %% i IN (% FILE1%)  DO SET DATE1 = %% ~ ti FOR %% i IN (% FILE2%) DO SET DATE2 = %% ~ ti IF "% DATE1%" == "% DATE2%" ECHO Файлы имеют одинаковый возраст и amp; & amp; & amp;  GOTO END FOR / F %% i IN ('DIR / B / O: D% FILE1%% FILE2%') DO SET NEWEST = %% i ECHO Новый файл% NEWEST%: END  
32
ответ дан Dave Webb 15 August 2018 в 17:47
поделиться
  • 1
    Я хотел бы добавить, что это решение работает только в том случае, если два файла находятся в одной папке. – Pete Magsig 29 August 2013 в 19:14
  • 2
    – Dave Knight 19 September 2014 в 11:16
  • 3
    Привет, не могли бы вы объяснить ('DIR / B / O: D% FILE1%% FILE2%') ? Я действительно не понимаю эту линию. – user15964 14 May 2015 в 12:01
  • 4
    @ user15964 DIR% FILE1%% FILE2% делает список каталогов, ищущих два файла, и поэтому должен всегда возвращать два файла. Добавление / O: D помещает их в порядок дат, а / B делает вывод "bare" поэтому это только имена файлов, а не размер файла и т. д. – Dave Webb 14 May 2015 в 12:40
  • 5
    @DaveWebb Большое спасибо – user15964 15 May 2015 в 14:12

На основе Ответ Wes Я создал обновленный скрипт. Обновления получили слишком много, чтобы добавить комментарии.

  1. Я добавил поддержку еще одного формата даты: формат, включая точки в датах. Добавлены инструкции о том, как включить больше форматов дат.
  2. Ответ Wes на самом деле не работал, поскольку cmd не может сравнивать целые числа размером более 1 + 31 бит, поэтому я исправил это с преобразованием числовых строк в цитируемые
  3. Скрипт может рассматривать отсутствующие файлы как самые старые файлы.
  4. Добавлена ​​поддержка второй точности.

Моя версия ниже .

  Использование @REM: @REM: getfiledatestr file-path envvar Результат @REM, возвращаемый в% envvar%: getfiledatestr для %% A в (% 1) do (установить getfilefolderstr = %% ~  dpA set getfilenamestr = %% ~ nxA) @REM Удаление конечной обратной косой черты, если% getfilefolderstr: ~ -1% == \ set getfilefolderstr =% getfilefolderstr: ~ 0, -1% @REM очистить его для случая, когда команда forfiles не работает set getfiledatestr  = for / f "delims =" %% i in ('"forfiles / p" "% getfilefolderstr%" "/ m" "% getfilenamestr%" "/ c" cmd / c echo @fdate @ftime ""') do  set getfiledatestr = %% i @REM старый код: для %% f in (% 1) установить set getfiledatestr = %% ~ tf установить% 2 = @REM считать  отсутствующие файлы как самые старые файлы, если «% getfiledatestr%» equ «" set% 2 = "" @REM В настоящее время поддерживаемые разделители разделов даты: / :.  и пространство.  Возможно, вам придется добавить дополнительные разделители в следующую строку, если ваш формат даты также содержит альтернативные разделители.  Если вы этого не сделаете, то разобранные даты будут полностью произвольно структурированы, а сравнения - неправильными.  for / f "tokens = 1,2,3,4,5,6 delims = / :." %% a in ("% getfiledatestr%") do (@REM для MM / DD / YYYY HH: MM: SS AMPM  использовать вызов: appendpadded% 2 %% c %% b %% a %% g %% d %% e %% f @REM для DD / MM / YYYY HH: MM: SS AMPM использовать вызов: appendpadded% 2 %% c  %% b %% a %% g %% d %% e %% f @REM для YYYY / DD / MM HH: MM: SS AMPM использовать вызов: appendpadded% 2 %% a %% b %% c %% g  %% d %% e %% f call: appendpadded% 2 %% c %% b %% a %% g %% d %% e %% f) @goto: eof @REM Принимает env var в качестве первого параметра  @REM и значения, которые будут добавлены в качестве остальных параметров, @REM правое заполнение всех значений с ведущими 0 до 4 мест: appendpadded set temp_value = 000% 2 call: expand set% 1 = %%% 1 %%%% temp_value:  ~ -4 %% shift / 2, если «% 2» neq »« goto appendpadded set temp_value = @REM cmd не может сравнивать целые числа, превышающие 1 + 31 бит, поэтому вместо этого преобразуйте их в цитированные числовые строки.  Текущая реализация генерирует числовые строки намного дольше, чем 31-битные целые числа.  call: expand set% 1 = "%%% 1 %%%" @goto: eof @REM заставляет все переменные полностью развернуться: expand% * @goto: eof  
9
ответ дан Community 15 August 2018 в 17:47
поделиться
  • 1
    Есть одна проблема, которую я нашел сегодня. Это будет думать, что 12:00 PM новее, чем 1:00 вечера, так как 12 больше, чем 1. Я изменил «если% originalHourPart% LSS% secondHourPart% goto старше & quot; к ", если% originalHourPart% LSS% secondHourPart% goto check12 & quot; и добавил это -: check12 if% secondHourPart% EQU 12 goto newer goto постарше – Evan Zimmerman 2 October 2015 в 14:30
  • 2
    вместо того, чтобы повторно использовать сравнение дат, почему бы не скопировать один файл в другую папку и использовать оригинальный ответ? намного быстрее, и намного чище. Просто обратите внимание, чтобы сохранить время изменения файла при копировании. – ciuly 27 November 2015 в 00:14

серьезно, вы должны начать изучать что-то еще. Это не шутка. DOS (cmd.exe) серьезно не имеет возможности манипулирования датами и многих других недостатков. Ниже приведена следующая лучшая альтернатива, предусмотренная, помимо DOS, vbscript

  Установить objFS = CreateObject ("Scripting.FileSystemObject") Установить objArgs = WScript.Arguments strFile1 = objArgs (0) strFile2 = objArgs (1  ) Установить objFile1 = objFS.GetFile (strFile1) Установить objFile2 = objFS.GetFile (strFile2) Если objFile1.DateLastModified & lt;  objFile2.DateLastModified Затем WScript.Echo «File1:» & amp; strFile1 & amp; »старше, чем« & amp; strFile2 Else WScript.Echo »File1:« & amp; strFile1 & amp; »новее, чем« & amp; strFile2 End If  [  ! d5] 

запустите его в командной строке

  C: \ test & gt; dir Громкость на диске C не имеет метки.  Объемный серийный номер 08AC-4F03 Справочник C: \ test 11/06/2009 07:40 PM & lt; DIR & gt;  ,  11/06/2009 07:40 PM & lt; DIR & gt;  .. 11/06/2009 06:26 PM 135 file 11/02/2009 04:31 PM 4,516 m.txt C: \ test & gt; cscript / nologo test.vbs файл m.txt Файл1: файл новее, чем m.txt   

Конечно, в новых версиях окон вы можете попробовать Powershell ...

8
ответ дан ghostdog74 15 August 2018 в 17:47
поделиться
  • 1
    Благодарю. Вы правы в DOS. Для личных сценариев я использую Bash в Cygwin. При написании небольших утилит, которые будут использоваться командой, мне нужно использовать язык, доступный для всех. Здесь широко распространен Python. (Это также имеет кросс-платформенное преимущество.) Но Python является «языком сценариев». а не «язык оболочки», и поэтому нерегулярные подпроцессы требуют большей работы. Ваше предложение VBScript является хорошим; возможно, я должен начать понимать это. Я избегал «Powershells», преднамеренно, потому что Microsoft, похоже, не в состоянии решить их должным образом. – Rhubbarb 6 November 2009 в 13:11
  • 2
    @rhubbarb - Powershell поставляется на Windows 7 и Windows Server 2008 R2, и я думаю, что Powershell также широко используется Exchange 2007. Таким образом, он определенно поддерживается должным образом. Это стоит проверить, так как это довольно здорово. – Dave Webb 6 November 2009 в 13:18
  • 3
    Если вы используете Python, вы должны использовать его повсюду. Не имеет значения, является ли его языком сценариев или языком оболочки. Это просто имя. Важно то, что Python (и его Немезида Perl) может делать почти все оболочки или (DOS). Перемещение / копирование файлов, разбор, захват веб-страницы ... Практически вам нужно всего лишь 1 хороший и простой в использовании инструмент для выполнения всех ваших задач администрирования / программирования. AS для вышеуказанной проверки старых / более новых файлов, вы можете использовать os.getmtime () для Python для проверки измененного времени. – ghostdog74 6 November 2009 в 13:23
  • 4
    когда возникает такая ситуация, всегда первое, что нужно сделать, проверьте pypi (или найдите интернет) для модулей, которые делают то, что вы хотите. Я уверен, вы можете найти модули для svn, которые работают с Python. таким образом вам не нужно вызывать внешний процесс. Если на самом деле нет выбора, вы должны использовать модуль подпроцесса, у вас все еще будет преимущество превосходных возможностей Python для синтаксического разбора. :) – ghostdog74 6 November 2009 в 13:48
  • 5
    Вы правы в написании сценариев, и я бы сказал, что DOS - это самый худший язык сценариев, язык которого сосредоточен вокруг «для файлов» ... однако в визуальной студии (по крайней мере до VS 2015) событие построения возможно только в синтаксисе DOS. – yoel halb 1 July 2015 в 06:54

Для конкретной ситуации, когда вы хотите сделать что-то в стиле Makefile, перезаписывая файл назначения на основе исходного файла, только если исходный файл является более новым, я придумал этот отвратительный, но простой метод. Это только вариант, если вы никоим образом не беспокоитесь о существующем содержимом целевого файла, который старше исходного файла.

  для / f "delims =" %% r in  ('xcopy / D / Y / f / e "% inputdir% \% source_filename%" "% outputdir% \% dest_filename%"') do (IF "%% r" EQU "1 Файл скопирован"% build_command  %!% inputdir% \% source_filename% ""% outputdir% \% dest_filename% ")  

Что это такое, xcopy только перезаписывает файл назначения, если исходный файл более новый. Если оно не новее, %% r «Скопировано 0 файлов», поэтому условная команда не выполняется, а целевой файл никогда не перезаписывается. Если он новее, %% r «Скопирован 1 файл (ы)», поэтому ваш файл назначения вкратце является копией исходного файла, затем выполняется команда сборки, заменяя его новой версией того,

Возможно, я должен был просто написать скрипт perl.

(Примечание: вы также можете xcopy обрабатывать ситуацию, в которой место назначения файл изначально не существует, поместив звездочку в конец имени файла назначения, если вы этого не сделаете, тогда xcopy не уверен, является ли назначение именем файла или папки, и там не имеет значения по умолчанию для ответа на имя файла.)

5
ответ дан Harmlezz 15 August 2018 в 17:47
поделиться
  • 1
    Хороший трюк, потому что он независим от локали. Давайте сделаем еще один шаг: xcopy / DYLR src & quot; dst * & quot; | findstr / BC: "0" & gt; nul & amp; & amp; @echo dst новее , это не перезаписывает dst , просто проверяет, существует ли оно и новее. Да, необходима звездочка – robert4 17 September 2015 в 15:37
  • 2
    @ robert4 - это лучший ответ! – rich p 9 June 2016 в 14:51
  • 3
    Спасибо за трейлинг-трюк. Это первый раз, когда я упоминал об этом. Единственное предыдущее решение, которое я видел, - это «эхо f» в xcopy, которое является липким. – Richard A 18 April 2018 в 06:53

Вот более простое решение. Объединив части даты как одну строку от наиболее значимого до наименее значимого, мы можем просто провести сравнение строк по результату.

Другими словами, сравнение значений YYYYMMDDAMPMHHMM даст желаемый результат без необходимости индивидуально сравнить каждый сегмент даты. Это значение получается путем конкатенации различных частей строки даты, извлеченных второй командой FOR.

  call: getfiledatestr path \ file1.txt file1time call: getfiledatestr path \ file2.txt file2time if  % file1time% equ% file2time% (echo path \ file1.txt - это тот же возраст, что и путь \ file2.txt с точностью до минуты) else if% file1time% lss% file2time% (echo path \ file1.txt старше пути \  file2.txt) else (echo path \ file1.txt новее, чем путь \ file2.txt) goto: eof @REM use: @REM: getfiledatestr file-path envvar @REM результат возвращается в% envvar%: getfiledatestr для %% f  in (% 1) do set getfiledatestr = %% ~ tf @REM для MM / DD / YYYY HH: использование MM AMPM: appendpadded% 2 %% c %% b %% a %% f %% d %% e @  REM для DD / MM / YYYY HH: использование MM AMPM: appendpadded% 2 %% c %% b %% a %% f %% d %% e @REM для YYYY / DD / MM HH: использование MM AMPM:  appendpadded% 2 %% a %% b %% c %% f %% d %% e set% 2 = for / f "tokens = 1,2,3,4,5,6 delims = /:" %% a  in ("% getfiledatestr%") do (call: appendpadded% 2 %% c %% b %% a %% f %% d %% e)  @goto: eof @REM Принимает env var в качестве первого параметра @REM и значения, добавляемые в качестве остальных параметров, @REM справа заполняет все значения с ведущими 0 до 4-х мест: appendpadded set temp_value = 000% 2 call: expand  set% 1 = %%% 1 %%%% temp_value: ~ -4 %% shift / 2, если "% 2" neq "" goto appendpadded set temp_value = @goto: eof @REM заставляет все переменные полностью расширяться: expand%  * @goto: eof  
7
ответ дан Wes 15 August 2018 в 17:47
поделиться
  • 1
    Поскольку рецензенты, похоже, рассматривают мои обновления и «обращаются к автору», - независимо ... Я добавляю свои обновления в виде комментариев. Пожалуйста, бесплатно отредактируйте. 1. Обновление: @ REM В настоящее время поддерживаемые разделители разделов даты: / :. и пространство. Возможно, вам придется добавить дополнительные разделители в следующую строку, если ваш формат даты также содержит альтернативные разделители. Если вы этого не сделаете, то разобранные даты будут полностью произвольно структурированы, а сравнения неверны. для / f "токенов = 1,2,3,4,5,6 delims = / :. & Quot; %% a in ("% getfiledatestr%") делают ( – Roland Pihlakas 2 March 2015 в 19:05
  • 2
    Поскольку рецензенты, похоже, рассматривают мои обновления и «обращаются к автору», - независимо ... Я добавляю свои обновления в виде комментариев. Пожалуйста, бесплатно отредактируйте. 2. Обновление: set temp_value = @ REM cmd не может сравнивать целые числа больше 1 + 31 бит, поэтому вместо этого преобразуйте их в строки. Текущая реализация генерирует числовые строки намного дольше, чем 31-битные целые числа. call: expand set% 1 = "%%% 1 %%%" @ goto: eof – Roland Pihlakas 2 March 2015 в 19:06
  • 3
    meta о предложении редактирования: Предлагаемое редактирование . – Deduplicator 2 March 2015 в 19:35
  • 4
    Чтобы дать возможность сопоставлять даты с неэксентируемыми датами файла (без этого скрипта обновления с ошибкой, с этим обновлением он считает неэксентирующий файл старше): Update 3: add if & quot;% getfiledatestr% & quot; equ "& quot; установите% 2 = " до @ REM В настоящее время поддерживаются разделители разделов дат ... для / f" токенов = 1,2,3,4,5, 6 delims = / :. & Quot; %% a in ("% getfiledatestr%") делают ( – Roland Pihlakas 3 March 2015 в 22:50
  • 5
    Я добавил дополнительные обновления для поддержки точности секунд и на основе всех обновлений был создан новый ответ здесь: stackoverflow.com/a/29019902/193017 – Roland Pihlakas 12 March 2015 в 21:50