Всем привет! Сегодня я хочу поделится с вами более лёгким и правильным, с моей точки зрения, способом достижения аналогичного описанному в статье пользователя NikitaTrophimov результата.
Думаю, нет смысла повторно писать вводную часть — автор оригинальной статьи это сделал до меня — и, так как моя статья вряд ли увидела бы свет, не напиши он свою, и является всего лишь альтернативным видением способа решения задачи, то я сосредоточусь на главном.

Как и автору оригинальной статьи, мне представлялось весьма странным поведение команды «cd» (или «chdir») в cmd.exe. Казалось нелогичным, что для смены активного диска необходимо каждый раз выполнять дополнительные действия. Являясь поклонником интерфейса командной строки, я не раз пробовал улучшать внешний вид и возможности стандартного командного интерпретатора Microsoft Windows, но о возможности изменить стандартное поведение команды «cd» раньше даже не задумывался. После прочтения вышеупомянутой статьи на Хабре мне не давало покоя ощущение чрезмерной нестандартности и сложности описанного способа… а желание создать свой собственный велосипед и поскорее уже начать им пользоваться привело к кучке паре-тройке часов потраченного в ближайший выходной времени на разбор полётов. Итак, кому интересны мои изыскания — добро пожаловать под кат!

Небольшой ликбез по теме (можно не читать)
Стандартным механизмом для изменения поведения команд/программ «по умолчанию» (что справедливо для всех известных мне операционных систем) являются аргументы запуска, параметры, указываемые через пробел после имени команды или исполняемого файла. Именно этот механизм позволяет изменить поведение команды для смены текущей директории в cmd.exe на нужное нам. Указанный при вызове команды «cd» (или «chdir») параметр "/d" позволяет одновременно со сменой текущего каталога изменять и активный диск.

Ещё одним стандартным механизмом, использующимся для настройки параметров окружения «под себя» является механизм alias -ов. Хорошо известный и часто применяемый в среде Unix подобных операционных систем, он часто оказывается обделённым вниманием и даже вообще незаслуженно позабытым в Microsoft Windows. Этот механизм позволяет назначить свои собственные имена вызова для команд, программ, пар команда/программа+параметры и, что самое главное, позволяет изменить поведение стандартных команд и программ, т.к. алиасы имеют больший приоритет по сравнению с командами оболочек и программами, найденными оболочкой в директориях, указанных в переменной окружения «PATH».

Именно этим мы и воспользуемся. Приступим!

Постановка задачи: Команда «cd» должна автоматически изменять активный диск, если в качестве аргумента передан путь к данным на отличном от текущего диске.

Решение: Казалось бы чего проще? Используя «doskey» создаём алиас «cd=cd /d $*» и радуемся жизни… но вот в чём загвоздка — ломается стандартное поведение команды «cd» при запуске без параметров. Запущенная без параметров, эта команда является полным аналогом команды «pwd» из оболочек Unix подобных операционных систем и должна бы выдавать на консоль информацию о текущей директории, но после задания алиаса она уже будет выполнятся с ключом "/d", наличие которого подразумевает и наличие следующего параметра — пути, по которому следует перейти. Не обнаружив его — команда выдаст на консоль сообщение об ошибке и завершит работу. Такое решение нас явно не устраивает!

После некоторого количества размышлений, вдумчивого просмотра страничек Хабра и активного Гугления родилось следующее решение — а почему бы не написать .bat файл? Постойте, не спешите закидывать меня помидорами, я и сам не любитель костылей. Решение было вполне продуманным и, как вы сейчас увидите, имеющим шанс оказаться рабочим.

Моя идея состояла в следующем — я решил написать .bat файл, принимающий аргументы и запускающий стандартную команду «cd» с переданными ему аргументами. В случае, если аргументов запуска у файла нет — он запускает команду «cd» без аргументов (режим вывода текущей директории), если аргументы есть — добавляет перед ними ключ "/d" и выполняет команду «cd» с ключом "/d" и переданными ему аргументами. Т.е. при использовании этого решения мы получаем желаемое — работает стандартное поведение команды «cd» без аргументов и работает автоматическая смена диска.

@echo off

if "%*" == "" (
    cd
) else (
    cd /d "%*"
)

exit /b


Итак, мы уже получили рабочее решение, но это ещё не то, что нам нужно. Осталось заменить стандартную команду смены директории, и в этом нам поможет механизм alias -ов. Сохраняем полученный .bat файл в одну из директорий, описанных в переменной «PATH» (к примеру в %WINDIR%\System32), с именем cd.bat и создаём алиас командой «doskey cd=cd.bat $*». Всё бы хорошо, но алиас сохранится только до закрытия текущего окна cmd.exe… надо исправить ситуацию! Создаём ещё один .bat файл для автоматической установки переменных окружения при запуске окон cmd.exe — cmd_env.bat, который так же сохраняем в выбранную директорию рядом с cd.bat

@echo off

doskey /macrofile="%USERPROFILE%\aliases"

exit /b


Также необходимо создать простой текстовый файл «aliases» и разместить его в %USERPROFILE%

cd="%WINDIR%\System32\cd.bat" $*

и .reg файл для активации автоматического запуска cmd_env.bat при открытии cmd.exe

Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\Software\Microsoft\Command Processor] "Autorun"="C:\\Windows\\System32\\cmd_env.bat"

Сохраняем его, к примеру, с именем cmd_env_reg.reg

Импортируем параметры из файла cmd_env_reg.reg в реестр и запускаем cmd.exe любым доступным способом. Готово! Проверяем результат!

Данное решение было успешно протестировано на работоспособность в среде Windows 2008 R2, 7, 2003 R2, XP.

PS: Большое спасибо автору оригинальной статьи за то, что подтолкнул меня к действию. Без его статьи я ещё долго терпел бы неудобства и мечтал о том, что «будет время — займусь».

PPS: Файл cmd_env.bat можно и нужно использовать для настройки cmd.exe — к примеру, для задания стандартных цветов в консоли командой «color 02» или для установки переменных окружения.

PPPS: Ссылки для интересующихся темой — ConEmu, Clink, cmder и прочие — Console2 и её форк ConsoleZ, rCons, WinQConsole

Комментарии (14)


  1. saboteur_kiev
    20.07.2015 16:50
    +2

    Второй батник для подгрузки алиасов писать не обязательно.
    Можно просто прописать ключ

    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\cd]
    @=«c:\\mytools\\cd.bat»

    И что примечательно, даже в PATH класть файл не обязательно. Будет работать сразу.
    Фича работает начиная с win2007
    Есть также ветки и для отдельных пользователей, чтобы создавать личные, а не глобальные профайлы.


  1. padla2k
    20.07.2015 17:43

    Не то что бы я очень не люблю cmd, но что вам мешает использовать powershell вместо cmd? Тем более что с 5 версии он стал вообще лапочкой и теперь еще и синтаксис команд подсвечивает. Что такого можно делать в cmd что было бы менее удобно, чем в powershell?


    1. mutin_sa Автор
      20.07.2015 18:09
      +1

      За исключением подобных описанным в статье мелочей, меня вполне устраивает cmd.exe а возможности PowerShell для моих задач избыточны и… в PowerShell не работает Far Manager. Возможно есть и другие причины, но я их сейчас не помню.


  1. svyatogor
    20.07.2015 19:53

    нежелания разбираться с «особенностями» cmd.exe привело меня к установке cygwin. получаем замечательно работающий шел (любой на выбор) и богатейшие возможности настройки. фар конечно не запустишь там, это конечно минус.


    1. wrewolf
      20.07.2015 20:22

      mc


      1. svyatogor
        20.07.2015 21:31
        +3

        mc и far сравнивать нельзя, слишком разные весовые категории.


  1. RumataEstora
    21.07.2015 00:00
    +1

    Во-первых, if "%*" == "" приведет к ошибке в случае кавычек в аргументе

    U:\tmp>cd /d "z:\tmp"
    The syntax of the command is incorrect.
    

    Надо if "%~1" == "". Хотя это тоже не спасение.

    Во-вторых, cd.bat — лишняя сущность. Достаточно
    doskey cd=if "$*" == "" ( cd ) else ( cd /d $* )
    


    1. RumataEstora
      21.07.2015 00:13
      +2

      И можно расширить:

      doskey cd=if "$*" == "" ( cd ) else if "$1" == "~" ( cd /d ^"^%USERPROFILE^%^" ) else ( cd /d $* )
      


  1. ffwd
    21.07.2015 14:59

    Вместо таких ухищрений, можно использовать PUSHD и POPD для навигации по папкам (доступно начиная с Win XP).


    1. saboteur_kiev
      21.07.2015 15:26

      Идеальное решение. Прописать алиас в реестре cd на pushd и все, теперь всегда и все работает со всеми каталогами.


    1. mutin_sa Автор
      22.07.2015 04:15

      У этого решения есть одна особенность — при переходе в сетевой каталог по UNC-пути, происходит автоматическое подключение сетевой папки как диска с назначением свободной буквы диска. Причём это происходит при КАЖДОМ переходе в любую сетевую папку. Автоотключения диска не происходит, т.е. очень быстро у Вас закончатся свободные буквы для дисков и вы не сможете подключить к примеру Flash-карту… а в Моём компьютере будете наблюдать кучу сетевых дисков. Как минимум, в Windows 2008 R2 это решение приводит к такому результату. На других версиях не проверял.


  1. onix74
    21.07.2015 15:36
    +2

    И после всего описанного здесь, у кого-то повернётся язык назвать линуксоида красноглазиком?! :-)

    Вообще, было интересно почитать, но использовать я всё же не стану. Добавить "/d" не большая проблема. По-моему, даже меньшая, чем выполнять всё описанное на всех обслуживаемых серверах. Кроме того, подобное решение отучает от стандартного поведения стандартных команд и может доставить неудобство при работе на неподготовленных хостах. Впрочем, это всего лишь моё мнение.


    1. mutin_sa Автор
      22.07.2015 04:29

      Полностью согласен с Вашей точкой зрения. :)


  1. Alexeyslav
    21.07.2015 17:18

    Хм, а разве дефолтное поведение команды не может быть задано через параметры SET(переменные окружения) как это делается с командой DIR? на счет CD не знаю, но для DIR такие настройки тянутся еще с MS-DOS 6.20 по меньшей мере.
    Очень жаль что такое не сделали.