Announcement

Collapse
No announcement yet.

quoting quotes in param string for SHELL

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • quoting quotes in param string for SHELL

    I'm trying to create a SHELL statement that will successfully execute the commandline from msg#4 in another recent thread (https://forum.powerbasic.com/forum/u...top-connection).

    Code:
     netstat -n | find ":3389" | find "ESTABLISHED"
    I'm having trouble with proper syntax passing DQs to CMD.exe...

    I'm asking because I want to know how to manage these levels of syntax translation. (In fact, I've succeeded in getting the info by skipping the pipes to FIND, and simply redirecting the NETSTAT -n into a tempfile, then using PB to open that file and have PB do the find...) But I still would like to learn this DQ syntax thing...


    Based on straight syntax in a CMD window vs attempt from a .BAT file, I see that DQs need to be tripled! So I've tried a bunch of things; here's the jumble of tests...

    I'm compiling under PBCC 6.04

    Oh BTW, :3389 is not on my machine, so I used one that was. But for the sake of consistency in this thread, my code below uses the same one mentioned above.

    Thanks in advance for any constructive comments or pointers to info that I can study!
    -John



    Code:
    #Compile Exe
    #Dim All
    
    Function PBMain () As Long
    Local lExitCode As Long
    Local m As String
    
    'Shell "NETSTAT -n | find " & $DQ & ":3389" & $Dq & " | find " & $Dq & "ESTABLISHED" & $Dq, exit to lExitCode 'most straightforward; won't run
    
    'm = "||" & "NETSTAT -n | find " & $DQ & ":3389" & $Dq & " | find " & $Dq & "ESTABLISHED" & $Dq & "||" ' use || as marker to confirm string is as expected
    'm = $Dq & "NETSTAT -n | find " & $Dq & ":3389" & $Dq & " | find " & $Dq & "ESTABLISHED" & $Dq & " > tempfile.txt" & $Dq 'try redirecting to a file
    
    'm = "NETSTAT -n | find " & $Dq & $Dq & $Dq & ":3389" & $Dq & $Dq & $Dq & " > tempfile.txt" 'try reduced command with triple DQs
    m = "NETSTAT -n " ' try simplest command to verify it is even being run! (yes it runs)
    
    'm = "NETSTAT -n | find " & $DQ & ":3389" & $Dq & " > tempfile.txt" ' verify redirection works
    
    ? m
    Shell m , Exit To lExitCode ' use message as above
    Shell $Dq & m & $Dq, Exit To lExitCode ' enclose the whole damn thing in an extra set of DQs...
    ? "lExitCode = " & Trim$(lExitCode)
    
    waitkey$
    
    End Function


    Another approach...

    Code:
    'try forcing another shell
    'Shell ENVIRON$("COMSPEC") & " /C " & $DQ & m & $DQ & " > tempfile.txt", Exit To lExitCode
    SHELL ENVIRON$("COMSPEC") & " /C " & m & " > tempfile.txt", EXIT TO lExitCode

  • #2
    Never mind. (But I think caret-escapes will be involved.)
    Last edited by Eric Pearson; 10 Feb 2018, 01:45 PM. Reason: Because I can.
    "Not my circus, not my monkeys."

    Comment


    • #3
      Thanks Eric,

      Before your "Because I can" edit, I played with the idea of the param to the .BAT, but really, it's more about learning how to construct that string so that CMD.exe will run it.

      Not sure about "carat escapes". I'll start looking that up in a few minutes.

      So, to prove that NETSTAT will actually run, this minimalist command works:

      Code:
      SHELL "netstat -n"
      But as soon as I add the pipe character:

      Code:
      SHELL "netstat -n | find " & $DQ & ":3389" & $DQ
      ...NETSTAT returns its built-in Help...

      As you can see from all my attempts in the post#1 code, I also tried tripling the DQs, but NETSTAT returns the built-in help...

      So... any other ideas?

      Thanks,
      -John

      Comment


      • #4
        > it's more about learning how to construct that string

        Right, that's why I removed the original suggestion.

        Google "cmd caret". It has been an escape character since XP.

        A possibly useful nugget: Each segment of a piped command is executed in its own copy of CMD, so maybe the segments need to be quoted?
        "Not my circus, not my monkeys."

        Comment


        • #5
          So this thread just showed me a bug in the 10.03 PBWin compiler. It doesn't check for terminating quotes in the Shell statement, so this compiles fine and passes the entire line from the NETSTAT to straightforward to Shell.
          Code:
          Shell "NETSTAT -n | find :3389 | find ESTABLISHED, exit to lExitCode 'most straightforward
          Anyway, as mentioned, piping and redirection are cmd.exe facilities, Shell just CreateProcess's whatever you send it. So the version with %COMSPEC% is what you need, since netstat itself has no idea what to do with pipes.

          You need to create this:
          cmd.exe /K "netstat -n | find ":443" | find "ESTABLISHED""

          I never liked the & $dq & stuff, just creates a lot of noise IMO, so I escape the quotes inline
          Code:
          Function PBMain () As Long
          Local lExitCode As Long
          Local m As String
          
          m = USING$("""&"" /K ""netstat -n | find "":443"" | find ""ESTABLISHED""""", ENVIRON$("COMSPEC"))
          
          ? m
          
          Shell m EXIT TO lExitCode
          
          End Function
          Since there's millions of quotes, this breaks down to
          Code:
          m = USING$(
          " ' opening literal quote
             ""&"" ' quoting cmd.exe path
              /K ' first arg
              "" ' start of cmd.exe's second arg
                 netstat -n | find "":3389"" | find ""ESTABLISHED"" ' command we want with quoted parameters
              "" ' end of cmd.exe second arg
          " ' ending literal quote
          , ENVIRON$("COMSPEC"))

          Comment


          • #6
            > PBWin compiler (...) doesn't check for terminating quotes in the Shell statement,

            PB doesn't check for terminating quotes, period. It's a longstanding early-BASIC spec that Bob insisted on following.
            "Not my circus, not my monkeys."

            Comment


            • #7
              Eric, I appreciate your suggestions! The more I explore, the more I see how much I don't know. Humbling.

              Bob, "netstat itself has no idea what to do with pipes." DOH! THAT's what had been escaping me! yes, bad pun, I know... I just couldn't resist.

              Also,
              1. I most definitely appreciate your "breakdown" explanation. I'm working through each line/piece; lots of stuff in that is new to me! So it's VERY helpful.
              2. I do not understand what USING$ is doing, so I'm going over the Help also... I'm trying to figure out what advantage it had over a straight concatenated string...
              3. I did not realize that the PB compiler would accept multiple double-quotes "inline". I never even gave that a try. I'm going to have to run experiments to see where that's OK and where it isn't. Or is that a by-product of using USING?

              So OK, I've got my Sunday afternoon planned now: lots of reading, experimenting, and studying...

              Thanks to both of you for your helpful thoughts!
              -John

              Comment


              • #8
                ...Hmmm...

                With the string from Bob's message, I can see that the commandline receives the proper syntax: that is, it runs just fine when I hand-type it into a CMD window's commandline.

                BUT when run from the PB code, the FIND command always reports "No such file or directory".

                From FIND's /? built-in help, and from the MSDN explanation of FIND, I would conclude that the filter is expecting its input to be coming from a file, not the previous command. So, the command string must still not be in the correct format.

                But I cannot tell what needs to be different in order to work "as intended"... (#DoWhatIWantNotWhatIType is not yet a Windows setting..)

                -John

                Comment


                • #9
                  > I'm going to have to run experiments to see where that's OK and where it isn't.

                  Everywhere. It's kind of buried in the Help:

                  A string literal can include the double-quote character, simply by doubling the character within the string. For example:

                  A$ = "This is a ""string"""

                  "Not my circus, not my monkeys."

                  Comment


                  • #10
                    This seems to work ok.
                    Code:
                    #DIM All
                    #COMPILE EXE
                    #INCLUDE "WIN32API.INC"
                    
                    FUNCTION PBMAIN()
                    
                      Shell Environ$("Comspec") + " /K " + "netstat -n" + "|" + "find "":3389""" + "|" + "find ""ESTABLISHED""", 1
                    
                    END FUNCTION
                    '------------------/PBMain
                    cmd result

                    Where 192.168.0.6 is the targeted PC and 192.168.0.7 is the PC running the remote desktop session.
                    The app shown above is on the target PC and launched via the remote desktop session from 192.168.0.7.
                    Last edited by Dave Biggs; 11 Feb 2018, 05:50 PM. Reason: Comments added
                    Rgds, Dave

                    Comment


                    • #11
                      Having runs a couple dozen variations of my own code and on code provided by others, I was still having no success...
                      FIND was always causing NETSTAT to return its built-in Help...

                      Finally, I decided to track down FIND.exe and see whether that was maybe not properly in the PATH or some such.

                      Went to the various Windows/system* folders and looked for "FIND*.exe" and surprise! In addition to FIND.EXE, there exists FINDSTR.exe, in both system32 and SysWOW64 folders.

                      So I changed Dave Bigg's code from FIND to FINDSTR, and it worked perfectly. ...makes me wonder why the two different programs, and what the diffs...

                      Since I had already been able to do: FIND /? and see its Help, I decided to do the same for FINDSTR /? Quite a difference! (See below)

                      And the file dates are interesting - FIND matches the date of the original install of the OS. FINDSTR is about a year later. Each shares its file date with many other utilities in the folder... An OS Upgrade?

                      So I'm about to start re-testing my original "problem" code, using FINDSTR instead of just FIND, and see if I was close to being right at the start... (just for my own satisfaction).

                      Thanks for all the suggestions above. It's been very helpful for my edumication.

                      -John




                      Code:
                      Microsoft Windows [Version 6.1.7601]
                      Copyright (c) 2009 Microsoft Corporation.  All rights reserved.
                      
                      C:\Windows\system32
                      2018-02-12
                      >find /?
                      Searches for a text string in a file or files.
                      
                      FIND [/V] [/C] [/N] [/I] [/OFF[LINE]] "string" [[drive:][path]filename[ ...]]
                      
                        /V         Displays all lines NOT containing the specified string.
                        /C         Displays only the count of lines containing the string.
                        /N         Displays line numbers with the displayed lines.
                        /I         Ignores the case of characters when searching for the string.
                        /OFF[LINE] Do not skip files with offline attribute set.
                        "string"   Specifies the text string to find.
                        [drive:][path]filename
                                   Specifies a file or files to search.
                      
                      If a path is not specified, FIND searches the text typed at the prompt
                      or piped from another command.
                      
                      C:\Windows\system32
                      2018-02-12
                      >findstr /?
                      Searches for strings in files.
                      
                      FINDSTR [/B] [/E] [/L] [/R] [/S] [/I] [/X] [/V] [/N] [/M] [/O] [/P] [/F:file]
                              [/C:string] [/G:file] [/D:dir list] [/A:color attributes] [/OFF[LINE]]
                              strings [[drive:][path]filename[ ...]]
                      
                        /B         Matches pattern if at the beginning of a line.
                        /E         Matches pattern if at the end of a line.
                        /L         Uses search strings literally.
                        /R         Uses search strings as regular expressions.
                        /S         Searches for matching files in the current directory and all
                                   subdirectories.
                        /I         Specifies that the search is not to be case-sensitive.
                        /X         Prints lines that match exactly.
                        /V         Prints only lines that do not contain a match.
                        /N         Prints the line number before each line that matches.
                        /M         Prints only the filename if a file contains a match.
                        /O         Prints character offset before each matching line.
                        /P         Skip files with non-printable characters.
                        /OFF[LINE] Do not skip files with offline attribute set.
                        /A:attr    Specifies color attribute with two hex digits. See "color /?"
                        /F:file    Reads file list from the specified file(/ stands for console).
                        /C:string  Uses specified string as a literal search string.
                        /G:file    Gets search strings from the specified file(/ stands for console).
                        /D:dir     Search a semicolon delimited list of directories
                        strings    Text to be searched for.
                        [drive:][path]filename
                                   Specifies a file or files to search.
                      
                      Use spaces to separate multiple search strings unless the argument is prefixed
                      with /C.  For example, 'FINDSTR "hello there" x.y' searches for "hello" or
                      "there" in file x.y.  'FINDSTR /C:"hello there" x.y' searches for
                      "hello there" in file x.y.
                      
                      Regular expression quick reference:
                        .        Wildcard: any character
                        *        Repeat: zero or more occurrences of previous character or class
                        ^        Line position: beginning of line
                        $        Line position: end of line
                        [class]  Character class: any one character in set
                        [^class] Inverse class: any one character not in set
                        [x-y]    Range: any characters within the specified range
                        \x       Escape: literal use of metacharacter x
                        \<xyz    Word position: beginning of word
                        xyz\>    Word position: end of word
                      
                      For full information on FINDSTR regular expressions refer to the online Command
                      Reference.
                      
                      C:\Windows\system32
                      2018-02-12
                      >



                      Comment


                      • #12
                        Don't use PB "SHELL" for this... in fact don't use the command shell at all (I think the rules change across command-shell versions!) .

                        Instead, use an approved (?) Win API call such as CreateProcess() or ShellExecuteEx() and you never need quotes except those you want to be passed to the launched program.

                        Starter demo: Win 32: Monitor Process with ShellExecuteEx June 22, 2001

                        MCM



                        Comment


                        • #13
                          Michael, thanks for that link. I'll start checking it out later tonight. Having seen all these oddities, I am happy to try something else if it will be more reliable.

                          Just out of curiosity, does anyone else have both FIND.EXE and FINDSTR.EXE in their Windows\SysWOW64 directory?

                          Thanks,
                          -John

                          Comment


                          • #14
                            > does anyone else have both

                            Yes. The properties dialog of Find refers to grep, and Findstr to qgrep.
                            "Not my circus, not my monkeys."

                            Comment


                            • #15

                              Originally posted by John Montenigro View Post
                              Michael, thanks for that link. I'll start checking it out later tonight. Having seen all these oddities, I am happy to try something else if it will be more reliable.

                              Just out of curiosity, does anyone else have both FIND.EXE and FINDSTR.EXE in their Windows\SysWOW64 directory?

                              Thanks,
                              -John
                              Yep, and they are quite different FINDSTR is FIND on steroids - it supports regular expressions:
                              Code:
                              C:\Users\Stuart>find /?
                              Searches for a text string in a file or files.
                              
                              FIND [/V] [/C] [/N] [/I] [/OFF[LINE]] "string" [[drive:][path]filename[ ...]]
                              
                                /V         Displays all lines NOT containing the specified string.
                                /C         Displays only the count of lines containing the string.
                                /N         Displays line numbers with the displayed lines.
                                /I         Ignores the case of characters when searching for the string.
                                /OFF[LINE] Do not skip files with offline attribute set.
                                "string"   Specifies the text string to find.
                                [drive:][path]filename
                                           Specifies a file or files to search.
                              
                              If a path is not specified, FIND searches the text typed at the prompt
                              or piped from another command.
                              
                              C:\Users\Stuart>findstr /?
                              Searches for strings in files.
                              
                              FINDSTR [/B] [/E] [/L] [/R] [/S] [/I] [/X] [/V] [/N] [/M] [/O] [/P] [/F:file]
                                      [/C:string] [/G:file] [/D:dir list] [/A:color attributes] [/OFF[LINE]]
                                      strings [[drive:][path]filename[ ...]]
                              
                                /B         Matches pattern if at the beginning of a line.
                                /E         Matches pattern if at the end of a line.
                                /L         Uses search strings literally.
                                /R         Uses search strings as regular expressions.
                                /S         Searches for matching files in the current directory and all
                                           subdirectories.
                                /I         Specifies that the search is not to be case-sensitive.
                                /X         Prints lines that match exactly.
                                /V         Prints only lines that do not contain a match.
                                /N         Prints the line number before each line that matches.
                                /M         Prints only the filename if a file contains a match.
                                /O         Prints character offset before each matching line.
                                /P         Skip files with non-printable characters.
                                /OFF[LINE] Do not skip files with offline attribute set.
                                /A:attr    Specifies color attribute with two hex digits. See "color /?"
                                /F:file    Reads file list from the specified file(/ stands for console).
                                /C:string  Uses specified string as a literal search string.
                                /G:file    Gets search strings from the specified file(/ stands for console).
                                /D:dir     Search a semicolon delimited list of directories
                                strings    Text to be searched for.
                                [drive:][path]filename
                                           Specifies a file or files to search.
                              
                              Use spaces to separate multiple search strings unless the argument is prefixed
                              with /C.  For example, 'FINDSTR "hello there" x.y' searches for "hello" or
                              "there" in file x.y.  'FINDSTR /C:"hello there" x.y' searches for
                              "hello there" in file x.y.
                              
                              Regular expression quick reference:
                                .        Wildcard: any character
                                *        Repeat: zero or more occurrences of previous character or class
                                ^        Line position: beginning of line
                                $        Line position: end of line
                                [class]  Character class: any one character in set
                                [^class] Inverse class: any one character not in set
                                [x-y]    Range: any characters within the specified range
                                \x       Escape: literal use of metacharacter x
                                \<xyz    Word position: beginning of word
                                xyz\>    Word position: end of word
                              
                              For full information on FINDSTR regular expressions refer to the online Command
                              Reference.
                              --
                              [URL="http://www.camcopng.com"]CAMCo - Applications Development & ICT Consultancy[/URL][URL="http://www.hostingpng.com"]
                              PNG Domain Hosting[/URL]

                              Comment


                              • #16
                                As Eric mentioned, if you have to do a lot of this string searching you should look around for a Windows' implementation of (the UNIX origin) "grep" utility.

                                I've used 'grep' on Unix and I think someone had one for Windows and it's a lot more powerful than the canned MS-DOS/Windows' "Find."

                                I never used the mentioned 'FINDSTR' but that certainly looks quite powerful, too.

                                Comment


                                • #17
                                  And what's MORE interesting (to me, since what I thought the problem was - quoting DQs -- turned out to be something very different) is that the same syntax that works perfectly with FINDSTR, generates the error message "No such file or directory" with FIND.

                                  And I struggle against all my reflexes to ask "WHY?" ... I already KNOW that's a useless pursuit...

                                  -John

                                  ...and no, the Help file provides NO indication ...

                                  Comment


                                  • #18
                                    One other thing which can help: Instead of adding the $DQ 'inline' is to put the portion of the string containing the $DQ into a variable, as John did near the bottom of
                                    Post #1 This thread

                                    That is, you separate the use of double quotes into what is data (where it is always $DQ) and what is syntax used by the compiler when parsing (where double quote is "").

                                    That may sound like a little thing but it's served me well for a long time.

                                    MCM

                                    Comment

                                    Working...
                                    X