Цикл Batch FOR / F не будет считывать относительный каталог

#loops #batch-file #for-loop #text

#циклы #пакетный файл #цикл for #текст

Вопрос:

У меня есть простой цикл FOR / F, который удаляет все текстовые файлы, кроме одной строки:

 for /f "skip=12 tokens=* delims= " %%f in (.NonProcessed*.txt) do (
   > newfile.txt echo.%%f
   goto :eof
)
  

Но когда я запускаю, я получаю результат:

 The system cannot find the file .NonProcessed*.txt
  

Цикл for работает нормально, если я ввожу полный путь к текстовому файлу в скобках, но он не может обработать относительную ссылку, которая у меня там есть. Я смог использовать точно такую же относительную ссылку в другом стандартном цикле for в другом пакетном файле, запущенном в том же каталоге, без каких-либо проблем. Я не могу понять, почему это не сработает! Пожалуйста, помогите.

РЕДАКТИРОВАТЬ: Для комментариев код, который я использую сейчас, является

 for %%f in (.NonProcessed*.txt) do (
  echo f is %%f
  for /f "usebackq skip=12 tokens=* delims= " %%a in (%%f) do (
    echo a is %%a
    > %%f echo.%%a
    goto :continue
  )
:continue
  sqlcmd stuff here
)
  

Ответ №1:

Извините, но for /f это не позволяет вам этого сделать. И нет, проблема не в относительном пути к файлам, а в подстановочном знаке.

Согласно документации, у вас есть синтаксический регистр

 for /F ["ParsingKeywords"] {%% | %}variable in (filenameset) do command [CommandLineOptions]
  

В этом случае в документации указано The Set argument specifies one or more file names . Вы можете сделать

 for /f %%a in (file1.txt file2.txt file3.txt) do ...
  

но подстановочные знаки не разрешены.

Если вы не знаете имя файла, который хотите обработать, лучшим вариантом будет добавить дополнительную for команду для первого выбора файла

 for %%a in (".NonProcessed*.txt"
) do for /f "usebackq skip=12 tokens=* delims= " %%f in ("%%~fa"
) do (
   > newfile.txt echo(%%f
   goto :eof
)
  

При выполнении goto команда отменит оба for цикла, так что вы получите то же поведение, которое ожидали от своего исходного кода.

отредактировано для адаптации кода к комментариям

 @echo off

    set "folder=.NonProcessed"

    pushd "%folder%"
    for /f "tokens=1,2,* delims=:" %%a in (
        ' findstr /n "^" *.txt ^| findstr /r /b /c:"[^:]*:13:" '
    ) do (
        echo Overwrite file "%%a" with content "%%c"
        >"%%a" echo(%%c
    )
    popd
  

Прочитайте все файлы в папке, пронумеровав строки. Вывод для первой команды findstr будет

 filename.txt:99:lineContents
  

Этот вывод анализируется для нахождения строки 13, результирующие данные разделяются с использованием двоеточия в качестве разделителя, поэтому в конце мы будем указывать имя файла в %%a , номер строки в %%b и содержимое строки в %%c .

Комментарии:

1. Привет, спасибо за ответ. На самом деле, ваше решение — это то, что я уже пробовал! К сожалению, goto:eof отменит оба цикла на первой итерации. Очевидно, что я хочу выполнить цикл по всем текстовым файлам в папке с одинаковым поведением. Есть еще код вне «цикла изменения текста», но внутри внешнего цикла (он выполняет некоторый SQL). Чтобы добраться до этого, я только что сделал еще одну закладку вне внутреннего цикла перед этим дополнительным кодом и изменил goto:eof на goto:continue . Похоже, что это почти правильное поведение (оно работает только с одним файлом).

2. Однако по какой-то причине при работе с несколькими файлами возникают проблемы с пробелами в имени файла (но только при достижении во внутреннем цикле). Я получу код через минуту…

3. Хм, если у меня в папке более одного файла, он работает с первым, но явно не запускает внешний цикл для выбора следующего файла после его завершения. Это как-то связано с моим goto:continue ?

4. @user3804579, извините, в вопросе четко не указано, нужно ли вам перебирать больше, чем файл, или если вы просто априори не знаете имя файла. Хорошо, несколько файлов, на что должно заканчиваться newfile.txt ? Это просто временный файл для каждой итерации?, должен ли он содержать по одной строке из каждого файла? ….

5. Хорошо, фактическое требование заключается в том, чтобы для каждого файла в папке переписать файл, используя только содержимое 13-й строки

Ответ №2:

 SET FILES_LIST=files_list.config
DIR /b .NonProcessed*.txt>!FILES_LIST!
for /f "skip=12 tokens=* delims= " %%f in (!FILES_LIST!) do (
   > newfile.txt echo.%%f
   goto :eof
)
IF EXIST "!FILES_LIST!" DEL "!FILES_LIST!"
  

Я не проверял, как работает ваш FOR, просто добавил к нему свои дополнения / исправления…. Надеюсь, у вас это сработает.
С наилучшими пожеланиями!