Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

Comment on

( #3333=superdoc: print w/replies, xml ) Need Help??

OK, then the first step is to learn about the different types of "DOS" commands. DOS and Windows have a long and ugly history, and you need to learn a little bit of that history if you want to do more than just pushing the mouse over the desktop. My ancient DOS manuals distinguished between three types of DOS commands:

  1. Internal commands, meaning commands built into
  2. External COM commands, i.e. commands compiled and linked into the COM format (no header, fixed start offset, one shared segment for code and data, limited to max. 64k-256 bytes)
  3. External EXE commands, i.e. commands compiled and linked into the EXE format (header, variable start offset, multiple segments for code and data, nearly unlimited size)

One day, the DOS developers decided to look at the file data instead of the file extension when running external commands, so it was possible to rename EXE files to *.COM and vice versa. This allowed them to compile and link commands as EXE files while still using a COM file extension for backwards compatibility.

So, you really need to distinguish between internal and external commands.

With Windows 2000, XP, and newer, things become a little bit complicated, they inherited a very similar, but still different command shell named cmd.exe from the NT line, which behaves different and has different build-in commands. Of course, each Windows version has its own version of cmd.exe, all with different features. cmd.exe is the default shell on 2000 and newer, but is still there.

dir, cls, echo and a few others are internal commands, i.e. you have to invoke them using or cmd.exe. Typically, you prefix the desired command with /c or cmd.exe /c, depending on the OS version and on which implementation of the command you want to execute.

The majority of commands are external commands, most of then are EXE files, a few are renamed to *.COM for backwards compatibility. These commands can be executed directly, just like you would execute any other application (because that's what they are).

The next DOS / Windows history lession is the command line. Unix shells expand, interpret and split the command line and pass an array of parameters to the invoked program. If you type foo *.txt *.asc into a Unix shell, the foo program is typically invoked with a list of all txt and asc files in the current directory. DOS and Windows shells do not expand or split the command line, instead, they pass it as a single string to the invoked program. If you type foo *.txt *.asc into a DOS or Windows shell, the foo program gets *.txt *.asc as a single command line string, and has to expand and split it in its very own way.

Most DOS and Windows programs delegate that to the C runtime library (or equivalent), and so most DOS and Windows programs expand the command line in a very similar way. But there is no guarantee for that.

Under DOS, the command line was limited to 126 bytes due to the COM file format, and sometimes, you still run into this limit.

The DOS / Windows shells still process the command line, e.g. they replace environment variables or remove redirections from the command line, so the command line is not passed completely unmodified to the invoked program. The rules to prevent this from happening (i.e. quoting) differ from shell to shell, and from OS version to OS version

So invoking the DOS shell really begs for trouble. (Not that unix shells are paradise, their quoting rules are a little bit simpler, but still differ from shell to shell.) Obviously, avoiding the shell as much as possible prevents problems. For exec and system, this means to use the multi-argument form. When you call exec or system with a single argument, perl may pass that argument to a random shell, leaving you with a lot of problems.

On Windows, things become again problematic here, as there is no way to pass an array of parameters to the invoked program. Perl has to generate a single command line string from your arguments. And you have to hope that perls algorithm to construct the string is compatible with the invoked program's algorithm to split it again into an array.

I/O redirection is once again problematic on Windows. On Unix, you fork, modify I/O and environment as needed in the forked copy of the current process, and then execute the real child, which inherits I/O redirection, environment and so on. On Windows, you have to do all this when creating a new process using the CreateProcess API function, and for more tricks, you need the CreateProcessEx API function. (I wonder when Microsoft will reach CreateProcessExExExEx ;-)) Don't worry, perl.exe will handle most of this for you. But it is not perfect.

So, your really best bet on Windows is NOT to use external programs at all if you can avoid it.

You do not need dir, as I've explained before. copy and xcopy can be replaced by File::Copy and File::Copy::Recursive. For ftp, you have a load of CPAN modules, like Net::FTP, LWP::Simple, LWP::UserAgent. cd won't work at all, but you can use chdir and Cwd.

For many other commands, you will find superiour perl replacements, either build-in (e.g., the DOS find command is a crippled grep) or on CPAN. Only for very low-level access (fdisk, format, network config), you need either an external command or access to the Windows API. Often, Win32::API can be helpfull, sometimes DBD::WMI works, and if you are lucky, someone has already written a module and published it on CPAN, typically named Win32::Something.


Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

In reply to Re^3: why IPC::Open3 can't execute MS-DOS "dir" command? by afoken
in thread why IPC::Open3 can't execute MS-DOS "dir" command? by kiinoo

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and all is quiet...

    How do I use this? | Other CB clients
    Other Users?
    Others perusing the Monastery: (2)
    As of 2018-01-22 06:37 GMT
    Find Nodes?
      Voting Booth?
      How did you see in the new year?

      Results (232 votes). Check out past polls.