do shell script result concatination

I have a bunch of shell script one-liners like this:

set O to (do shell script "defaults read /Library/Preferences/ | grep -wA 1 -m 2 OriginX")

with different pref files, different grep arguments, and different search words from which I subsequently extract the word or words I want and assemble them into a big property list for easy access later.

Somehow, it seems very inefficient to call them one at a time, but entering them as a series separated by semicolons gives only the last as a result. How does one get a series of simple semicolon-delimited shell commands to keep adding to the standard output instead of replacing it so that a concatination of all the results is returned in only one shell script call?


Have you tried the pipeline? Whenever you want the output of one command to become the input of the next command, you put in a space, then the upright character: | and another space. (I don’t know the name of that character. It is on your keyboard as the Shift , right above the return key.)

The question I wonder, is how many of those babies can you string together in a single [do shell script] command?

Of course, you might also consider writing your own shell scripts, and accessing those from AS.

Pipes alone aren’t going to do what he needs, I’m afraid. He needs to loop through an array of domains a gather specific keys for each domain (which are different for each domain). This is certainly possible all on one line, but it’s going to be a crapload of difficult-to-read mess, especially the control statements.

He’s better off writing an actual shell script (not trying to do it in a one-liner) for this, calling that in the script, and gathering the result sent back to AppleScript (stdout) into a list of items.

Please note that the following is simply a conceptual example. I’ve been up all night, and I jotted this down off-the-cuff:

Now, the reason I didn’t just have it in a single nested loop is because bash doesn’t have actual two-dimensional arrays, and the script needs to read different sets of keys from different domains. This was easier than simulating a two-dimensional array (just not worth the effort here).

(Also note that bash arrays start at 0.)

Also, always remember to specify the path to the binaries of the commands you’re using, or you leave yourself open to $PATH exploits.

That’s bad.

That’s better.

Do that if you plan on doing anything more than a quick one-liner.

Some times, you can also:

do shell script "echo `defaults read x a`,`defaults read x b`,`defaults read x c`" --> "1,2,3"

When I try that, I get the equivalent of: “defaults read x a,defaults read x b,defaults read x c`”, i.e. bash just echos the rest of the command string, it doesn’t “do” the parts.

set O to (do shell script "echo 'defaults read /Library/Preferences/ | grep -wA 1 -m 2 OriginX', 'defaults read /Library/Preferences/ | grep -w -m 2 Height)'")
--> "defaults read /Library/Preferences/ | grep -wA 1 -m 2 OriginX, defaults read /Library/Preferences/ | grep -w -m 2 Height)"

I don’t know how is called this char, but note the differences between ` and '.

In this context, “`” is commonly called a backtick. (Wikipedia: Backtick/Grave accent)

On most US keyboards, this is the character directly to the left of the number 1 key.

Yes, jj, and it works too, whatever it’s called. Thanks. I had never noticed before that there was a difference. ` is ascii character 96, and is ascii character 39. Turns out you don’t need the commas either.

An extension to the question (never satisfied, sorry):

If you are reading and “greping” a number of defaults from the same pref file, is there a way to cascade the greps so you aren’t opening and closing the same document repeatedly? eg:

set LO to (do shell script "echo `defaults read /Library/Preferences/ | grep -wA 1 -m 2 OriginX``defaults read /Library/Preferences/ | grep -w -m 2 Height``defaults read /Library/Preferences/ | grep -w -m 2 Width``defaults read /Library/Preferences/ | grep -w  DisplayLayoutToRight`")

will open /Library/Preferences/ three times. man:grep doesn’t make it simple, so I suppose a RegEx is required that returns the pieces that match a set of patterns. Is that the way it would normally be done? This isn’t vital because the script above does what I want - I’m just interested in pursuing efficiency when collecting data from documents - not necessarily a preference file.