How to run bash shell command in awk?

Discussion in 'Mac Programming' started by mikezang, Aug 31, 2012.

  1. mikezang macrumors 6502a

    Joined:
    May 22, 2010
    Location:
    Tokyo, Japan
    #1
    I have a plist file as below
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <array>
    * <dict>
    * * <key>showName</key>
    * * <string>Name1</string>
    * * <key>videoURLString</key>
    * * <string>http://ip1/file1.txt</string>
    * </dict>
    * <dict>
    * * <key>showName</key>
    * * <string>Name2</string>
    * * <key>videoURLString</key>
    * * <string>http://ip2/file2.txt</string>
    * </dict>
    </array>
    </plist>
    
    I want to get showName and videoYRLString then run
    "curl $videURLString -o $showName"
    to download files, but I am not sure hot to do, pls help me.
    Code:
    plistfile="${HOME}/Downloads.plist"
    
    showName="$(/usr/libexec/PlistBuddy -c "Print" "${plistfile}" | awk '/showName = /{print $3}' | awk -F' ' '{print $1}')"
    videoURLString="$(/usr/libexec/PlistBuddy -c "Print" "${plistfile}" | awk '/videoURLString = /{print $3}' )"
    
    
    printf "%s\n" "${showName[@]}"
    printf "%s\n" "${videoURLString[@]}"*
    
     
  2. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #2
    There are several possible ways to perform curl on all the things that were found.

    One of the simplest is to do it all in 'awk'. Write a single awk program that has the following pattern-matches:
    • for the pattern /showName = /, append $3 to an array of names.
    • for the pattern /videoURLString = /, append $3 to an array of URLs.
    • for the special pattern END (see awk's man page), loop thru the names and URLs, performing the desired curl command using the system command.
    In short, use awk to perform all the matching, collecting, iterating, and curl'ing. Right now, you're only using awk as a variation of grep. It's much more powerful than that. Study the awk man page, and maybe look at a tutorial on awk that covers the BEGIN and END patterns.

    An alternative is to use a shell 'for' command to iterate over the arrays, and run curl on each indexed name and url. You might also use the 'xargs' command. Personally, I think both alternatives are more complex than simply using awk.
     
  3. mikezang thread starter macrumors 6502a

    Joined:
    May 22, 2010
    Location:
    Tokyo, Japan
    #3
    Thanks for yor reply. I am reading guide, for example, sed & awk, and so on.
    As you you know, it is not easy even if you read a lot of guide of programming, it need time, but I want to use it soon.
    Can you show me code to do what I need by awk?
     
  4. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #4
    This is an example as I described:

    File: example.awk
    Code:
    # array indexes zeroed
    BEGIN { n = 0; u = 0;  }
    
    # match patterns from PlistBuddy output
    /showName = /  { names[ n++ ] = $3; }
    /videoURLString = /  { urls[ u++ ] = $3; }
    
    # when no more input, process everything
    END {
      if ( n != u )  { print "Unequal counts, n: " n ", u: " u;  exit 1; }
    
      for ( i = 0; i < n; ++i ) {
        print "name", names[ i ], "url", urls[ i ];
        # build cmd-string and put system() here
      }
    }
    
    Command-line:
    Code:
    PlistBuddy -c print array.plist | awk -f example.awk
    

    This is a simpler one that runs curl incrementally.

    File: curly.awk
    Code:
    # keep name for later
    /showName = /  { name = $3 }
    
    # process name and url
    /videoURLString = /  {
      cmd = "curl " $3 " -o " name
      print "cmd:", cmd
    
      ## disabled for testing (inspect output for correctness)
    #  status = system( cmd )
    #  if ( status != 0 )  { print "curl failed:", status; exit status }
    }
    
    Command-line:
    Code:
    PlistBuddy -c print array.plist | awk -f curly.awk
    

    None of these account for the possibility of spaces in the name, quotes or other special characters in the name or URL, and probably various other shortcomings. This is why it's important to run tests first, and confirm the output looks correct WITHOUT running the curl command.

    You could also break it down into two parts. The first awk script simply produces the correct output, with the name first and the url second on each line. The second awk script then reads that list, and runs curl on $1 and $2. This is left as an exercise for the reader.
     
  5. mikezang, Sep 3, 2012
    Last edited by a moderator: Sep 3, 2012

    mikezang thread starter macrumors 6502a

    Joined:
    May 22, 2010
    Location:
    Tokyo, Japan
    #5
    Thanks for your samples! The first is good, but second seems has a bug, because I will get results as below, Name is shift..
    Code:
    cmd: curl http://ip1/file1.txt -o 
    cmd: curl http://ip1/file1.txt -o Name1
    
     
  6. chown33, Sep 3, 2012
    Last edited: Sep 3, 2012

    chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #6
    Post your real data.

    In particular, run the PlistBuddy command and redirect its output to a file. Look at that file very carefully, for reasons why it might produce the output shown, then post that file.

    Also post the actual plist that produces this output.


    The only data you've posted is in your initial post. And it's not even a real plist, because it contains *'s that must be removed. You need to show real data.
     

Share This Page