Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   [решено] for do copy создаёт лишний файл (http://forum.oszone.net/showthread.php?t=352008)

shadowbat 28-09-2022 09:34 2993191

for do copy создаёт лишний файл
 
Вложений: 1
есть два файла:
file.txt
file_2.txt

при запуске такого батника:
Код:

@echo off
chcp 1251
::for %%i in ("%CD%\*.txt") do (copy "%%i" "%%~dpni_new%%~xi")
for /R "%CD%" %%i in (*.txt) do (copy "%%i" "%%~dpni_new%%~xi")

создаётся не 2 файла, а 3. один из них лишний с двумя "_new"
Код:

file.txt
file_2.txt
file_2_new.txt
file_new.txt
file_new_new.txt

(если переименовать file_2.txt в zzz.txt, то ошибка пропадает и создаётся как и положено 2 файла)
(если в батнике поменять _new на -new, то ошибка пропадает и создаётся как и положено 2 файла)

в чём причина такой ошибки?

NickM 28-09-2022 11:00 2993200

А какая задача то у Вас?
Или Вы думаете, что кто-нибудь поймёт её из Вашего кода сценария?

shadowbat 29-09-2022 08:15 2993251

Цитата:

Цитата NickM
А какая задача то у Вас? »

задача - найти причину создания лишнего файла "_new"
если эта причина не будет найдена, то я поменяю "_new" на "-new" в коде и буду с этим жить

YuS_2 29-09-2022 08:42 2993252

Цитата:

Цитата shadowbat
задача - найти причину создания лишнего файла "_new" »

При некоторых условиях (правильных по синтаксису, но неправильных для корректного кода), в цикле for может образоваться "лишняя" итерация. Как раз, для Вашего случая...
Вот, код, который наглядно отображает эту "лишнюю" итерацию:
Код:

@echo off
set /a f=5 &:число создаваемых файлов в каталоге
set /a k=0 &:динамический счетчик для наименований файлов
set /a n=0 &:динамический счетчик для подсчета итераций

rem Если отсутствует, создаем каталог TEXT, рядом со сценарием:
set "d1=%cd%\text"
if not exist "%d1%" md "%d1%"

cd "%d1%"
setlocal enabledelayedexpansion
rem Создаем тестовые файлы:
if not exist "*.txt" (
        for /l %%i in (1,1,!f!) do rem: фигня>"!k!.txt"&set /a k+=1
)

rem Проверка лишней итерации в цикле:
echo.Файлов в каталоге:
dir /b/a-d
echo.--------------------------
echo.
echo.Переименование файлов циклом и собственно, "лишняя итерация":
for %%A in (*.txt) do (
        echo %%A

        rem Так проходов n+1 от количества файлов:
        rename "%%A" "!random!.txt"
       
        set /a n+=1
)
echo.
echo Проходов: !n!
echo.--------------------------
echo.
echo.Итоговое число файлов в каталоге:
dir /b/a-d
echo.
pause

Т.е. при наличии 5 текстовых файлов, цикл for выполняет 6 итераций...
Мораль: не выполняйте переименование файлов посредством цикла for, в одном и том же каталоге, где находятся исходные файлы. :)

megaloman 29-09-2022 10:10 2993255

shadowbat, Если интересно не только "почему", но и "как", то
Код:

@Echo Off
cls
>nul chcp 1251
        For /R "%CD%" %%i in (*.txt) Do >nul (Echo %%i|FindStr /E /I "_new%%~xi" ||copy "%%i" "%%~dpni_new%%~xi")
pause
Exit /B

Код:

@Echo Off
cls
>nul chcp 1251
        FOR /F "usebackq delims=" %%i IN (`2^>nul Dir "*.txt" /S /A:-D /B ^|FindStr /E /I /V "_new.txt"`) DO >nul copy "%%i" "%%~dpni_new%%~xi"
pause
Exit /B

При повторном запуске этих батников копий _new_new не будет, хотя минус - повторное копирование.
Поэтому лучше использовать xcopy /D
Код:

@Echo Off
cls
>nul chcp 1251
        FOR /F "usebackq delims=" %%i IN (`2^>nul Dir "*.txt" /S /A:-D /B ^|FindStr /E /I /V "_new.txt"`) DO Echo F|>nul xcopy /D "%%i" "%%~dpni_new%%~xi"
pause
Exit /B

Либо
Код:

@Echo Off
cls
>nul chcp 1251
        FOR /F "usebackq delims=" %%i IN (`2^>nul Dir "*.txt" /S /A:-D /B ^|FindStr /E /I /V "_new.txt"`) DO (
                If Not Exist "%%~dpni_new%%~xi" >nul copy "%%i" "%%~dpni_new%%~xi"
        )
pause
Exit /B


YuS_2 29-09-2022 11:00 2993257

Цитата:

Цитата shadowbat
в чём причина такой ошибки? »

Как альтернативу cmd, лучше изучайте powershell, возможностей у него больше... а также, более понятный синтаксис и легче для запоминания.
Ваша задача, на powershell:
Код:

$folder = '.\TEST'
$filter = '*.txt'
$pattern = '_new'

dir $folder -filter $filter -file|%{
        if($_ -notmatch $pattern){
                copy $_.fullname ($_.directoryname + '\' + $_.basename + $pattern + $_.extension)
        }
}


shadowbat 30-09-2022 16:38 2993342

megaloman
YuS_2
благодарю за помощь


Время: 17:23.

Время: 17:23.
© OSzone.net 2001-