The PUSHD/POPD Implementation in Pure Windows Batch

  • 时间:2020-09-16 12:48:17
  • 分类:网络文摘
  • 阅读:140 次

PUSHD/POPD is a great pair of tools that exist in modern operating system e.g. Windows, Linux or MAC. It allows you to jump forward and backwards between directories. The pushd takes a directory, before jumping, it will push the current directory to the stack, which we can popd later (restoring to previous directory). For example:

1
2
3
4
5
6
? pwd
/root
? pushd /abc
/abc
? popd
/root
? pwd
/root
? pushd /abc
/abc
? popd
/root

We are now implementing the PUSHD/POPD using Windows Batch Programming. You could save the following windows scripts using .cmd or .bat extensions. Even it has been provided on Modern windows command shell, it is still a good idiom/exercise to do so.

PUSHD.bat (Windows Batch Script)

The idea is to store the stack using the environment variable. We can store a stack index pointer for example, when PUSHD_COUNT environment variable is set to 1, the top of the stack (directory string) is stored in PUSHD0.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@echo off
if [%1] == [] (
    echo pushd: no other directory
    goto :eof
)
set TMP=%cd%
if [%TMP%] == [] (
    for /f %%f in ('cd') do (
        set TMP=%%f
    )
)
cd /d "%1" 2> nul
if [%errorlevel%] == [1] (
    echo pushd: %1: No such file or directory
    goto :eof
)
if [%PUSHD_COUNT%] == [] (
    set PUSHD_COUNT=0
)
set PUSHD%PUSHD_COUNT%=%TMP%
set /a PUSHD_COUNT=%PUSHD_COUNT+1
@echo off
if [%1] == [] (
    echo pushd: no other directory
    goto :eof
)
set TMP=%cd%
if [%TMP%] == [] (
    for /f %%f in ('cd') do (
        set TMP=%%f
    )
)
cd /d "%1" 2> nul
if [%errorlevel%] == [1] (
    echo pushd: %1: No such file or directory
    goto :eof
)
if [%PUSHD_COUNT%] == [] (
    set PUSHD_COUNT=0
)
set PUSHD%PUSHD_COUNT%=%TMP%
set /a PUSHD_COUNT=%PUSHD_COUNT+1

When we push a new directory using PUSHD, we first store the current directory string in environment variable PUSHD%PUSHD_COUNTER% then we increment the counter %PUSHD_COUNTER%.

To get the current directory in the Windows command shell, we can read the content from environment variable %CD%. In the ancient Windows System, when this is not set, you can use the following to parse the output of the CD command (into %CD% environment variable), which prints the current directory when no argument is given.

1
2
3
4
5
if [%CD%] == [] (
    for /f %%f in ('cd') do (
        set CD=%%f
    )
)
if [%CD%] == [] (
    for /f %%f in ('cd') do (
        set CD=%%f
    )
)

POPD.bat (Windows Batch Script)

Popd pops the directory string from the stack, and change to it by CD or CHDIR.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@echo off
if [%PUSHD_COUNT%] == [] (
    echo popd: directory stack empty
    goto :eof
)
set /a PUSHD_COUNT=%PUSHD_COUNT-1
set TMP=PUSHD%PUSHD_COUNT%
 
set TMPFILE=%RANDOM%.tmp
 
setlocal enabledelayedexpansion
if [!%TMP%!] == [] (
    echo popd: directory stack empty
    goto :eof
)
set TMPDIR=!%TMP%!
rem endlocal will erase the chdir and therefore 
rem saving the file in a temp file
echo %TMPDIR% > %TMPFILE%
endlocal
 
rem reading the directory from a file
set /p TMP=<%TMPFILE%
del /f %TMPFILE%
chdir /d "%TMP%"
 
set PUSHD%PUSHD_COUNT%=
@echo off
if [%PUSHD_COUNT%] == [] (
    echo popd: directory stack empty
    goto :eof
)
set /a PUSHD_COUNT=%PUSHD_COUNT-1
set TMP=PUSHD%PUSHD_COUNT%

set TMPFILE=%RANDOM%.tmp

setlocal enabledelayedexpansion
if [!%TMP%!] == [] (
    echo popd: directory stack empty
    goto :eof
)
set TMPDIR=!%TMP%!
rem endlocal will erase the chdir and therefore 
rem saving the file in a temp file
echo %TMPDIR% > %TMPFILE%
endlocal

rem reading the directory from a file
set /p TMP=<%TMPFILE%
del /f %TMPFILE%
chdir /d "%TMP%"

set PUSHD%PUSHD_COUNT%=

We first decrement the %PUSHD_COUNTER% stack pointer. If the counter variable is not found, we exit the script with message popd: directory stack empty. As we are evaluating a environment variable and the name is formed by another environment name, we need to use the !%NAME%! within the local scope of setlocal enabledelayedexpansion to do so.

One side-effect of setlocal is that it will erase/restore any states/changes after endlocal thus changing the directory within the local scope isn’t working. And the only way to pass the directory string outside the scope is to write it to the file, e.g. the %RANDOM% temporary file.

We can use the following batch syntax to read a file content and save it to an environment variable using the set /p syntax.

1
set /p NAME=<file.txt
set /p NAME=<file.txt

Remember to delete the temp file and clear the content of PUSHD%PUSHD_COUNT%. Also, we pass the /D parameter to allow the CD command to jump to a directory with a different drive letter e.g. from C: to D:

–EOF (The Ultimate Computing & Technology Blog) —

推荐阅读:
数学题:甲乙丙三人的平均年龄为22岁  数学题:在一块边长60m的正方形花坛四边种冬青树  数学题:用一根铁丝刚好焊成一个棱长10厘米的正方体框架  数学题:一艘船在静水中每小时行驶40千米  数学题:在AB两点之间等距离安装路灯  数学题:一种商品随季节出售  数学题:一个底面半径是6厘米的圆柱形玻璃器皿里装有一部分水  数学题:已知点D、E、F分别是BC、AD、BE上的中点  数学题:21个同学来取水果  数学题:四一班买了30只红气球和黄气球装点教室 
评论列表
添加评论