![]() |
get the value of a variable in a previous command, single line
I'm using a program that writes postscript files (it's abcmp2s, which formats music, but that isn't relevant). I want to write the file, then open the file in Preview.
With this particular program, it happens there's a work-around that lets me pipe standard input to 'open'… but it isn't ideal for a number of reasons, primarily that the postscript data goes straight to 'open' without being saved to a ps file first (so Preview opens a pdf translation of a temporary ps… if I want to do anything with the ps, I have to rummage around in tmp, or repeat the output without the pipe). Is there a way to say "the file that was created by the previous command"? Or a way to say "the value of this particular parameter of the previous command"? I'd like to say Code:
thisprogram … | open [the file I just made] -a PreviewCode:
thisprogram … -O [output destination] | open [output destination] -a Previewthanks for the help |
oh, or can I create variables with something like?
Code:
thisprogram … -O {thethingtoopen}[output destination] ; open $thethingtoopen -a Preview |
Usually you'd do this sort of thing by assigning the filename to a variable first, then use that variable in the two places.
Code:
destFile="MyStuff/Docs/foo.ps" |
Why not simply use a folder action to open any new/updated file in preview?
|
Vegas— The destination folder changes with the input file (but isn't nec. in the same path as the input file). Along the same lines, in the past I've repeatedly output to some particular file, overwriting whatever already there; I put that file in the dock, and Previewing the latest output was always one click away. Both that and folder actions are okay but not part of the workflow I'd like.
Hayne— cool, piping that does it. but… Manually entering the file name again is still quicker than setting the variable and referencing it twice. There's no simple way to say? Code:
| getfrompreviouscommand value(-O)Code:
destfile=[grep the word following -O in <text of prev command>](Maybe I just need to ask the author to build in a -p option, since he obviously has access to the output file's name. But where's the fun in that? ;) |
Quote:
Or you could make an alias or Bash function to do this - see the section on shell aliases in this Unix FAQ The arguments passed to the previous command are accessible via the Bash shell's history mechanism. E.g. the last argument of the previous command is $! |
Right… maybe I was wrong to think this belonged in Newcomers. I thought it would be a simple, "Yes, you're clearly new to unix: it's 'getlastvalueof -O'" or "here, I wrote this 'bobsGetLastValueOf'". I've glanced at your FAQ before, Hayne, and it really looks like a great resource… some day I'll print it out, get some OS X Unix books from the library, and learn it. But for now:
It's not in a script; it's a one-off command 'abcm2ps <inputfile.abc> -O <outputfile.ps>'. I won't bore you with the reasons, but the goal is to have the whole "export, then preview what was exported" command on one line (';'s are ok) without using any user-defined functions. Having it all on one line, I can't do '… -O output.ps; open -a Preview !!:$' Can I get '!#<second to last word>'? |
get the value of a variable in a previous command, single line
I'm using a command that creates a PostScript file (details irrelevant, though I can go into if anyone wants), and I want to follow it with a command to open that newly-created file in Preview. The destination of the first command's output is specified by its -O option. If I had two lines to work with, it'd be easy enough to always put -O at the end, and follow it with 'open -a Preview !!:$'… but I'm restricted to a single line (again, reasons irrelevant).
So far I'm running Code:
postscriptExporter -O <output.ps> … ; open -a Preview !#:21) grep !# for the word following -O, or 2) take the first word after -O in !# (or the second word of everything following -O in !#) all right there in the command, no shell function use, one line. Can I do that? On a related note, has anyone written a shell function to answer questions of the form "Last time I ran 'open', what application did I open with?" — that returns the value of a certain parameter from the last time you set it in a certain command? I'm imagining some sort of Code:
(!<commandName> AND !$<paramName>) |
eitchbar:
I have merged your new thread with the existing one on the same subject. Please don't start new threads when there is an existing one on the same (or similar) subject. If you think your thread is in the wrong forum section or titled incorrectly, contact one of the moderators and ask to have it moved/fixed. |
Hayne, you're just to fast for me! :o
|
Quote:
The context of use is far from irrelevant - it is often the most important part of a query. And why can't you use the $! mechanism I suggested earlier? Maybe show us a specific example, in full. And why can't you make use of shell conveniences like aliases & functions? |
Firstly, remember the key questions here are in post 8, not those before. (it's not at all clear to me that posts 1-7, merged here from a separate thread, don't address a question (cf. the first bit of code in post 8) quite different from the one I'm asking in this thread)
so… okay Hayne I can answer those questions… but really, the reasons have nothing to do with the command itself other than that they restrict it to one line, no new functions or aliases — they're all supra-terminal context: 1) those are the terms in which I'm defining the problem in Post 1-7 and Post 8 Part 1 (see also reason 5, below) 2) I'd like to be able to share this with friends of mine who use this exporter and who would be intimidated if not completely confused by bash profile tweaks, or temporary function and alias creation. 3) The word processor application I use to write and edit these files (analogous to your favorite TeX word processor) has an "export to ps" feature (analogous to publishing a TeX file), which pops up a window full of check- and text-boxes, and it has a little window showing the unix command that'll be run. You can manually edit the command — so you can paste in a "and open it up" snippet at the end, if you have such a snippet. Those same friends are much more comfortable exporting through this application's ui than at the command line. And the application will only send a single line. 4) I myself do this exporting at the command line, doing dozens of export-open repetitions in fairly quick succession as I tweak the formatting file (again, the TeX analogy). The command looks like 'theExporter <input> -f <format file> -e <range of line to export> -O <output.ps>', and I typically only change the export name — and up-arrow (I'm not embarrassed), change out1.ps to out2.ps, and double-click the icon in the neighboring Finder window is as fast as anything else I could do. Unless I could knock out the double-clicking (and in Post 8 I do just that— but with inelegant restraints on the order of terms in the export command) 5) It'd be cool, I'm new to manipulating the bash history, I imagine the second part of my question would be a useful function to have, it's the whole problem I want to tackle, and it's got to be possible If you see a way, within the limits intergral to the problem, to use a $! method to tackle Post 8, especially the more general part 2 (or even posts 1-7, in a more elegant way than I have in Post 8) awesome, please tell me about it. (if you've already explained, it was over my head.) all I can imagine is in-line variable declaration, of the sort 'theExporter <input> -O {what will now be called TheOutput<output.ps>}'… I wouldn't be too surprised if there was a way to do that, but I don't know how and would appreciate advice from anyone who does (though, again, I don't how it bears on the questions linked at the start of this post). (it would be sweet if this post didn't kill my chances of getting help on Post 8, but I wouldn't be too surprised by that either) |
I don't see any way to do it simply by adding stuff on that command-line. The problem is that Bash does the history expansion on the whole line before breaking it up into separate commands by looking at the semi-colons. So history-based stuff won't work.
I think the simplest way to get the functionality you want is to replace the current exporter command with a wrapper script that adds the "open this file" functionality. Here's one implementation of a wrapper script (in Perl): Code:
#!/usr/bin/perlThen save the Perl script I supplied above in a file with the same name as the existing exporter program and edit it to make the variable $exporterCmd refer to the actual name of the existing exporter program - you would use a plain text editor to do this (e.g. TextWrangler). Then make that file executable via the command: chmod +x theExporter (using the actual name of the file instead of "theExporter") and then move it to the folder where the existing (now renamed) exporter program is. After all that (which could be done by an installer script for use by your friends), all you'd need to do would be to add the "--open" option in the command-line presented by your GUI editor. It would run the wrapper script and the wrapper script would invoke the original exporter and then open the file using the 'open' command. |
Quote:
Quote:
The exporter allows '… <input.abc> -O =', which outputs a .ps with the same basename and in the same directory as the abc file (really, ".abc" - cute, no?). I hadn't used Perl until today: How can I get the part of the argument that isn't options? The order is flexible, so I can't $ARGV[n]. Do I have to use GetOptions to cut out everything that is an option? Once I get it, the renaming is fine: Code:
…as prev post…thanks! |
Quote:
GetOptions takes a list of option names (before the arrows) and the variables where the value of those options are to be put (after the arrows). For each option, you can specify if the option takes a value and what type of value that is, by supplying a letter after an '='. E.g. 'O=s' means that the "-O" option takes a string value. Quote:
Since I'm using the 'pass_through' in the configuration of GetOptions above, anything that it doesn't recognize as an option remains in the @ARGV array. So the name of the input file is there along with all the remaining options. If it were always the first thing, you could get it simply as $ARGV[0], but you say that it isn't necessarily the first. One way to go (and maybe the best, if the most work) would be to add the names of all of the supported options in the call to GetOptions and then reproduce them in the call to the original exporter command. Another (easier) possibility would be to just loop through the @ARGV array yourself (in the Perl script), checking each element to see if it starts with "-" and hence find the input filename (presuming that it is the first command-line argument that isn't an option). Of course you would need to know which of the options take a value and skip over the values as well. Start with a loop like this: Code:
foreach my $arg (@ARGV) |
Quote:
Quote:
Code:
foreach my $arg (@ARGV)As for the just-for-kicks project: Looks like I have enough to write the command that'll answer to "Tell me the value of the option -x in the most recent 'y'" — I'll work on that tomorrow and post what I come up with to see how my solution looks to more expert eyes |
What about using "tee"?
thisprogram | tee output.file | nextprogram "thisprogram" writes its output to stdout and pipes it to "tee". "tee" reads stdin and writes it to both "output.file" and stdout, piping stdout to "nextprogram". |
Quote:
The dot (.) is a special character in regular expressions (which is what Perl is looking for in the above construction). It matches any one character. You want a literal dot, so you need to escape it with a backslash: \. And you only want to match ".abc" at the end of the string, so you need to "anchor" it with a "$": Code:
if ($arg =~ /\.abc$/) # ends with .abc |
Quote:
Quote:
Quote:
Here's my "What was the last time this was done?" script, used historical <command> prints the bash !<command> historical <command> -o <option> prints the equivalent of bash "!<command>" which is also "!? -<option>?" historical <command> -O <option> -o, but prints the value of <option> -f and -F specify a history file. -O is broken, giving 'Error in option spec: "$saughtOption=s"' on the second GetOptions call, making this all a lot of unnecessary fanciness :( Any comments? (Besides chuckling at all my IFs - I can't help it, as a kid I cut my teeth on TI-BASIC. I assume I'm not close to taking advantage of Perl) Code:
#!/usr/bin/perl |
Perl doesn't expand/interpolate variables inside single quotes, so:
'$saughtOption=s' is taken literally - no variable interpolation. |
Hmm… that doesn't fix it. In the example
Code:
open -a PreviewCode:
my $historicalValue; |
Quote:
So that "open" is misplaced in @ARGV. But I don't see why that would prevent GetOptions from working. Note also that it is (IMHO) slightly strange to be assigning a scalar to an array with a statement like: @ARGV = $historicalUse; I would either use parentheses: @ARGV = ($historicalUse); or start with an empty array @ARGV=(); and then add the scalar with 'push': push(@ARGV, $historicalUse); But I guess it works, so it's just a matter of style. |
Quote:
@a = $x, $yis parsed as (@a = $x), $y;which is probably not what you want (and will give you a warning if you use warnings;). The warning is that $y is a useless evaluation in a void context, because it has no side-effects. Change it to have a side-effect, and the warning disappears: @a = $x, ++$y;parses as: (@a = $x), (++$y);Adding parentheses, as in: @a = ($x, $y);serves to change the grouping, but does not change the scalar-or-list nature of the assignment. What makes this a list assignment is the presence of a list on the left hand side of the assignment. These statements: @a = $x;are all parsed identically except for the varying numbers of superfluous parentheses. In all these cases, the right hand side is evaluated in list context because the left hand side is a list. A comma has different meanings in different contexts, so that in: ($x, $y) = @a;it's the comma on the left hand side of an assignment that creates the list. The parentheses are there only to make the comma bind tighter than the assignment. Parentheses are useful for delimiting an empty list, but they don't create one. You have to already be in list context for some other reason: @a = ; # syntax errorIn Perl, context is everything. The very meaning of an expression like "(7,8)" changes depending on its context. Learn to "follow the context", and Perl becomes less cryptic. |
| All times are GMT -5. The time now is 05:52 PM. |
Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2014, vBulletin Solutions, Inc.
Site design © IDG Consumer & SMB; individuals retain copyright of their postings
but consent to the possible use of their material in other areas of IDG Consumer & SMB.