Как ввести переменную внутри цикла for в powershell? Области видимости в Windows
Решил написать скрипт для сравнения двух папок на разных носителях (один на диске H:\, другой на диске D:\) под Windows. В случае резервного копирования может быть полезным. Написал следующий код:
for /F "tokens=*" %%d in ('dir /B /S /AD') do (
set ssd=d
echo %ssd%
set ssd=%ssd:H:\=D:\%
comp "%%ssd" "%%d"
cd %%d
echo "inside %%d"
)
Ожидается, что в цикле for будут рекурсивно пробегаться все вложенные папки и будет производиться сравнение папок командой comp.
Столкнулся с проблемой: команда set ssd=d не объявляет новую переменную. Это становится очевидно благодаря команде echo %ssd% - она просто печатает в консоли echo. Т.е. переменная ssd не создаётся вовсе! Думаю, что в цикле for своя область видимости и в Windows нужно как-то хитро объявлять подобные переменные. Подскажите пожалуйста, как это правильно делается?
Ответы (3 шт):
Если вы не пошутили насчёт PowerShell, приведя скрипт для cmd, то для рекурсивного сравнения файлов не требуются переменные.
gci -Recurse .\PAPKA\ | `
where { ! $_.PSIsContainer } | `
% { $_.FullName } | `
% { fc.exe "$_" "$($_.Replace('D:','H:'))" }
Этот скриптик
- рекурсивно пройдёт по всем файлам из папки с именем PAPKA (каталоги будут отфильтрованы инструкцией
where { ! $_.PSIsContainer }), - для каждого файла добудет строку, содержащую полный путь к файлу
- вызовет утилиту
fc.exe, заменив во втором параметре строкуD:на строкуH:
Если вам нужно именно comp, то замените fc.exe на comp.exe, хотя я бы не советовал.
Второе. В PowerShell нужно вызывать именно fc.exe, так как простое fc - это алиас на команду Format-Custom.
Действительно перепутал кучу интерпретаторов, поэтому решил проще решить задачу и написал скрипт на Python + CMD.
import os
def run_command(command):
res = os.popen(command)
for line in res:
print(line.encode('cp1251').decode("cp866"))
command = "dir /B /S /AD"
dirs_inside = list(os.popen(command))
for dir_ in enumerate(dirs_inside):
dirs_inside[dir_[0]] = dir_[1][:-1]
cur_dir = os.getcwd()
all_dirs = [cur_dir] + dirs_inside
disk = 'H'
command_template = 'comp "{path_1}" "{path_2}"'
for dir_ in all_dirs:
path1 = disk + dir_[1:]
path2 = dir_
cur_command = command_template.format(path_1=path1, path_2=path2)
run_command(cur_command)
В пакетных файлах области видимости всех переменных глобальные, проблема не в них. Проблема в том, что %%-переменные раскрываются в момент начала выполнения команды, а она у вас одна - весь цикл for.
Для решения этой проблемы следует использовать ENABLEDELAYEDEXPANSION и !!-переменные:
setlocal enabledelayedexpansion
for /F "tokens=*" %%d in ('dir /B /S /AD') do (
set ssd=d
echo !ssd!
set ssd=!ssd:H:\=D:\!
comp "!ssd!" "%%d"
cd %%d
echo "inside %%d"
)