Lotus1 has asked for the wisdom of the Perl Monks concerning the following question:

This is minor but I find it annoying. When I print 80 characters and then a newline on the Windows command prompt it prints a blank line after the line. The Linux command prompt doesn't do this. My workaround on Windows has been to only print 79 characters per line. My question is why? I don't know how to print a newline from a batch file or I would test it.

use warnings; use strict; print "-"x79,"\n"; print "1\n"; print "-"x80,"\n"; print "2\n"; print "-"x80; print "3\n"; __DATA__ --redirected to a file in Windows. ---------------------------------------------------------------------- +--------- 1 ---------------------------------------------------------------------- +---------- 2 ---------------------------------------------------------------------- +----------3 --appearance from Windows command line. ---------------------------------------------------------------------- +--------- 1 ---------------------------------------------------------------------- +---------- 2 ---------------------------------------------------------------------- +---------- 3 --appearance from Linux command line. ---------------------------------------------------------------------- +--------- 1 ---------------------------------------------------------------------- +---------- 2 ---------------------------------------------------------------------- +---------- 3

Replies are listed 'Best First'.
Re: [OT] Why does newline in Windows print as having width?
by Athanasius (Archbishop) on Aug 18, 2018 at 04:06 UTC

    Hello Lotus1,

    I assume that the windows for both your Linux and your Windows command prompts are exactly 80 characters wide? If so, the following one-liner:

    perl -we 'print "-" x 80; <STDIN>;'

    on Linux (actually Cygwin, in my case) will show the cursor at the end of the line; but the equivalent script on Windows:

    perl -we "print '-' x 80; <STDIN>;'

    shows the cursor on the following line. This means that terminating the line with a carriage return \r will take the cursor back to the beginning of the line of hyphens on Linux, but on Windows it cannot do so because the cursor is already on a new line befor the carriage return is printed. Likewise for Perl’s \n character: printing a newline at the beginning of a line results in the extra blank line you are seeing.

    If you know that your command window will always be exactly 80 characters wide, you can get the output you want on Windows by simply omitting the newline character altogether:

    print "-" x 80; print "2\n";

    — but, of course, this is not portable either across platforms or across Windows command prompts of different widths.

    You may be able to achieve what you want using the Win32::Console module (but so far I haven’t figured out how to use it :-( Why is the Synopsis missing from its documentation??).

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Hi Athanasius,

      You wrote:

      If you know that your command window will always be exactly 80 characters wide, you can get the output you want on Windows by simply omitting the newline character altogether:

      The third section of the test program I posted does exactly that. Often I print things to both the console and a log file so it's annoying that they don't look the same if I try to print a partition across the whole line. Limiting my output to one less than the line width takes care of it but I was curious if other monks noticed or cared. I realize it's a very minor issue.

      Update: I tried your one-liners with <STDIN>. That's a good demonstration of the issue. If someone wanted to print a full line of characters and then use \r or \b to overwrite characters they could in Linux but not in Windows. If I modify your one-liner for Windows like the following then I can overwrite characters but as soon as the last column is written to then the line advances.

      perl -we "print q(-)x79,qq(\b\b);<STDIN>;"

      Your demonstration shows the issue is that cmd.exe will advance as soon as the last column is printed to whereas Linux doesn't advance until one character past the last column. This shows it has nothing to do with one or two characters for '\n'.

Re: [OT] Why does newline in Windows print as having width?
by kcott (Archbishop) on Aug 18, 2018 at 03:54 UTC

    G'day Lotus1,

    From my *nix (macOS) command line, with my usual 120 CPL (characters per line), I see what you show in the first example (file in Windows); at 80 CPL, I see what you show in the third example (Linux command line).

    What CPL are you using for your Windows and Linux command line examples? How does the appearance change using different CPL settings?

    I don't have a Windows command line handy to perform any testing now, and I'm an infrequent Windows user, so I'm just guessing that the blank line before the "2" in the second example (Windows command line) is the result of wrapping at 80 CPL and the fact that "\n" is one character (newline) on Linux but two characters (carriage return + newline) on Windows. Do note that guessing is the operative word here.

    — Ken

      Hi Ken,

      I'm using 80 CPL which is the default for Windows and Linux. I'm using Raspbian Linux which is based on Debian. I realize that Linux uses just one character for newline and Windows uses two but 80+1 and 80+2 are both greater than 80. I suppose the answer to my question is that Windows implemented things differently than *nix style operating systems.

Re: [OT] Why does newline in Windows print as having width?
by Anonymous Monk on Aug 19, 2018 at 07:21 UTC

    My question is why?
    When you have such questions about something that has been evolving since the beginning of computer era, the answer is most probably "backwards compatibility". I'm sorry for having no references to back that statement, though.

    There is no easy solution because some users will happen to have terminals wider or narrower than 80 characters. If I were you, I would write a function to detect terminal width and print a horizontal line and the following message, like this:

    use Term::ReadKey; sub line_msg { my $msg = shift; my ($width) = GetTerminalSize(STDOUT); print '-'x$width, $^O eq 'MSWin32' ? '' : "\n", "$msg\n"; }

Re: [OT] Why does newline in Windows print as having width?
by Anonymous Monk on Aug 18, 2018 at 10:51 UTC
    Heh... In 1999 i had cmd.exe set to 120 chars wide... In batch @perl -le print

    or @echo;

Re: [OT] Why does newline in Windows print as having width?
by anonymized user 468275 (Curate) on Aug 20, 2018 at 09:54 UTC
    When addressing portability issues, it is usually an idea to check the value of $^O, which translates to $OSNAME if you use English. You can also get the terminal width using Term::Readkey and call the method GetTerminalSize. Note also that windows counts the characters and wraps irrespective of whether the characters are even visible.

    use Term::ReadKey; use English qw( -no_match_vars ); sub Print { if ( $OSNAME =~ /^MSWin/) my ($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize()); # nb in this case, in above only need the first var # but keep the brackets for my $chunk (@_) { chomp $chunk; for my $line (split /\n/, $chunk) { print $line . (length($line) == $wchar ? '' : "\n"); } } } else { print @_; } }

    One world, one people

      use English qw( -no_match_vars );

      See Devel::AssertOS Devel::CheckOS

      use Devel::CheckOS qw/ os_is /; use if os_is(qw/ Win32 /), 'MyFormatter::Win32', 'Print'; use if !!os_is(qw/ Win32 /), 'MyFormatter', 'Print'; ... Print(...);
        I studied these sources and they seem to be a wrapper for $^O. The docs for these modules justify their existence in two ways:-

        - that $^O is an ugly three characters.

        - that families like 'linux, bsd, unix,' are grouped into one.

        But the first justification would be better moved to the "use English" documentation, the pragma you seem to think is wrong and the second does not apply to the situation where the OP only wants to catch Windows. All that Devel::CheckOS does in this case is convert mswin32 to Win32.

        In addition I don't like some of the magic in these modules, requiring at one point a "no strict refs" for no very good reason.

        IMO, If you want to optmise $OSNAME, it would be better still to 'use English' and use 'something new' that adds a new variable like $OSFAMILY (*) to the set rather than interpreting $^O in a heavily over-engineered way (32k for the .tar.gz)

        (* update: and populated only once for the Perl process)

        One world, one people