* "jobs" command within substitution @ 2007-03-08 19:27 Micah Cowan [not found] ` <17393e3e0703081155o7a240628t49fae220ac9f49ae@mail.gmail.com> 0 siblings, 1 reply; 3+ messages in thread From: Micah Cowan @ 2007-03-08 19:27 UTC (permalink / raw) To: zsh-workers Hello, all. This is my first post to this group. I scoured the manpages and list archives, but could not find the answer I seek. My question, in a nutshell, is: How can I effectively use the "jobs" builtin command in producing the interactive prompt? -- THE PROBLEM -- The following line was the obvious choice (provided appropriate options are set), and indeed works fine in several other shells: : PS1='$(jobs | pjobs_gen_prompt)' : # pjobs_gen_prompt is a custom shell fn However, I've discovered that, the output of : echo $(jobs) is empty (apart from the spurious newline), even when executing "jobs" in the current shell would produce output. In fact, : ( jobs ) still produces the expected, same results as execution directly within the current shell. It might be argued, due to the language of POSIX ("The jobs utility shall display the status of jobs that were started in the current shell environment"), that it is not required to do so for /copies/ of the current shell environment: however, the case between $(jobs) and (jobs) should at least be consistent, since their behavior in POSIX is defined the same. I don't think the language in the standard is precise enough to warrant me claiming that this actually /breaks/ POSIX, but it seems against the likely /intentions/ at any rate, at least to me. My personal opinion is that this is a bug, but I'd be happy to hear explanations if this is intended behavior. -- WORKAROUNDS? -- Regardless of whether this is a bug or not, I still need a way to do what I want. You can get a very clear picture of what I'm trying to accomplish by downloading my script (it lacks spit and polish that I plan to add soon, so it's not the "official" version yet; but it's functional): http://micah.cowan.name/svn/promptjobs/trunk/prompt-jobs.sh ^^^ source this, DON'T execute it (it won't work). and sourcing it (". ./prompt-jobs.sh"). After this, run a couple of jobs in the foreground (say, "man man" or "ls | less") and then suspend them via Ctrl-Z. In bash, this will produce a prompt such as: micah(1:man 2:ls)$ The prompt will be colorized in color-supporting terminals. I wish to get the same effect in zsh. You can follow the same steps in zsh, and will get the colorized version of your prompt, but you won't get the joblists. In the case of bash, I'm actually not using command-substitution on the value of PS1, but I'm using bash's PROMPT_COMMAND to /set/ PS1's value via a command-substitution. This is because, when bash is interpolating the value from PS1, it treats the escape-sequence protectors \[ and \] (equivalent to zsh's %{, %}) before it does the command-substitution, which would cause pjobs_gen_prompt's \[, \] to be printed literally. Zsh treats %{ and %} after command-substitution, so that's not a problem. Is there any /other/ way to do this that will work, today, for zsh? Perhaps an equivalent to bash's PROMPT_COMMAND that I haven't found in the documentation, or some option I missed that will allow jobs within command substitution to produce the output I'm expecting? Thanks /very/ much for taking the time to read this length explanation. And, please let me know what you think of my little script :) -- Micah J. Cowan Programmer, musician, typesetting enthusiast, gamer... http://micah.cowan.name/ ^ permalink raw reply [flat|nested] 3+ messages in thread
[parent not found: <17393e3e0703081155o7a240628t49fae220ac9f49ae@mail.gmail.com>]
[parent not found: <45F070A9.5060502@cowan.name>]
* Re: "jobs" command within substitution [not found] ` <45F070A9.5060502@cowan.name> @ 2007-03-08 21:19 ` Matt Wozniski 2007-03-08 22:00 ` Micah Cowan 0 siblings, 1 reply; 3+ messages in thread From: Matt Wozniski @ 2007-03-08 21:19 UTC (permalink / raw) To: zsh-workers, zsh-users On 3/8/07, Micah Cowan wrote: > Matt Wozniski wrote: > > On 3/8/07, Micah Cowan wrote: > >> Hello, all. This is my first post to this group. > >> > >> I scoured the manpages and list archives, but could not find the answer > >> I seek. > >> > >> My question, in a nutshell, is: How can I effectively use the "jobs" > >> builtin command in producing the interactive prompt? > > > > Rather than trying to parse the output of the 'jobs' command, you > > might find yourself better suited by manipulating the variables > > $jobdirs, $jobstates, and $jobtexts. You correctly identified the > > problem that you're hitting - $(jobs) is running in a subshell that > > doesn't have any jobs in its job table. I agree, however, that (jobs) > > should also be blank, since it's also running in a subshell. If, > > however, you're dead-set on parsing the output of 'jobs', you could > > use a syntax like 'jobs > >(read jobtext; echo $jobtext)', which is a > > clever way to run jobs in the current shell and do the parsing in a > > subshell via process substitution. > > Myself, I'd prefer to see both subshells produce the same output as the > "current shell", as bash, pdksh and ksh do. However, dash goes the other > way and makes ( jobs ) emit nothing (for all its claims of being a POSIX > shell, though, dash is fairly broken in some respects, such as broken > arithmetic expansion and lack of a line-editor [which POSIX requires]). > I'd be interested in seeing what the OpenGroup committee has to say > about it, since the standard is far from clear on the subject. > > I was not familiar with the variables you mention above. However, I'm > not sure they solve the problem, as yet again, invoking them within a > command-substitution will produce no information. The same problem would > be true of using the other syntax you describe: I still have no > available means to run the commands every time the prompt is issued, > apart from within command substitution, which will kill the job-state > info. Is there any way to get what I want executing in the "current" shell? > > Also, had you meant to post this reply to the list? It appears to have > been sent to me only. Yes, of course, I had meant to send it to the list. My mistake. *sheepish grin*. So, you're right - the special variable $jobtexts wouldn't match up in the subshell, but you could do something like this: $ function precmd { export jt="" for i in ${(kv)jobtexts}; jt="$jt:${i%% *}" jt=${jt#:} } $ echo $jt 1:find:2:sleep $ echo $(echo $jt) 1:find:2:sleep And then you have a not-special, not-array version of jobtexts exported into the environment of subshells that you can manipulate however you want - and it even lets you remove the ugly dependence on awk. ;-) (precmd is a function that gets called every time the editor is about to display a prompt, FYI). Like I said, though - even though this should take no effort whatsoever to do with zsh - no more than 5 lines or so - it would be difficult to maintain compatibility with bash. The best way I can think of to do what you want, off the top of my head, is the following: function precmd { psvar[1]="" # For each key and each value in jobtexts for i in ${(kv)jobtexts}; do # Come up with a separator between psvar[1] and this text if [[ $sep == " " ]]; then sep=":" else sep=" " fi # Then tack it on to the end of psvar[1] - Removing from # the first space to the end of the element, if it has a space psvar[1]="${psvar[1]}$sep${i%% *}" done # Remove leading space we accidentally inserted psvar[1]=${psvar[1]# } } and # Tell the prompt to reference psvar[1] (%?v == psvar[?]) PS1='micah(%1v)' You don't even need to use prompt_subst. Frankly, I'd just make your script check for ZSH right off the bat and do it the simple way, leaving the complicated stuff for shells that don't give you an elegant solution. ~Matt ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: "jobs" command within substitution 2007-03-08 21:19 ` Matt Wozniski @ 2007-03-08 22:00 ` Micah Cowan 0 siblings, 0 replies; 3+ messages in thread From: Micah Cowan @ 2007-03-08 22:00 UTC (permalink / raw) To: Matt Wozniski; +Cc: zsh-workers, zsh-users Matt Wozniski wrote: > On 3/8/07, Micah Cowan wrote: >> Matt Wozniski wrote: >> > On 3/8/07, Micah Cowan wrote: >> >> Hello, all. This is my first post to this group. >> >> >> >> I scoured the manpages and list archives, but could not find the >> answer >> >> I seek. >> >> >> >> My question, in a nutshell, is: How can I effectively use the "jobs" >> >> builtin command in producing the interactive prompt? >> > >> > Rather than trying to parse the output of the 'jobs' command, you >> > might find yourself better suited by manipulating the variables >> > $jobdirs, $jobstates, and $jobtexts. You correctly identified the >> > problem that you're hitting - $(jobs) is running in a subshell that >> > doesn't have any jobs in its job table. I agree, however, that (jobs) >> > should also be blank, since it's also running in a subshell. If, >> > however, you're dead-set on parsing the output of 'jobs', you could >> > use a syntax like 'jobs > >(read jobtext; echo $jobtext)', which is a >> > clever way to run jobs in the current shell and do the parsing in a >> > subshell via process substitution. >> >> Myself, I'd prefer to see both subshells produce the same output as the >> "current shell", as bash, pdksh and ksh do. However, dash goes the other >> way and makes ( jobs ) emit nothing (for all its claims of being a POSIX >> shell, though, dash is fairly broken in some respects, such as broken >> arithmetic expansion and lack of a line-editor [which POSIX requires]). >> I'd be interested in seeing what the OpenGroup committee has to say >> about it, since the standard is far from clear on the subject. >> >> I was not familiar with the variables you mention above. However, I'm >> not sure they solve the problem, as yet again, invoking them within a >> command-substitution will produce no information. The same problem would >> be true of using the other syntax you describe: I still have no >> available means to run the commands every time the prompt is issued, >> apart from within command substitution, which will kill the job-state >> info. Is there any way to get what I want executing in the "current" >> shell? >> >> Also, had you meant to post this reply to the list? It appears to have >> been sent to me only. > > Yes, of course, I had meant to send it to the list. My mistake. > *sheepish grin*. So, you're right - the special variable $jobtexts > wouldn't match up in the subshell, but you could do something like > this: > > $ function precmd { > export jt="" > for i in ${(kv)jobtexts}; jt="$jt:${i%% *}" > jt=${jt#:} > } > > $ echo $jt > 1:find:2:sleep > > $ echo $(echo $jt) > 1:find:2:sleep > > And then you have a not-special, not-array version of jobtexts > exported into the environment of subshells that you can manipulate > however you want - and it even lets you remove the ugly dependence on > awk. ;-) > > (precmd is a function that gets called every time the editor is about > to display a prompt, FYI). precmd looks to be /exactly/ what I was looking for, then. I'll I was so focused on the bashism, that I was searching and re-searching the special parameters, rather than special functions. Thanks! Using jobtexts, etc is probably preferable to using the "jobs" output anyway, since zsh's appears to have a non-standard format (splitting a single job across lines), which will make my life more difficult. It's also probably more precise. I probably won't lose the awk dependency, though, since the awk script also does some clean-up on the command names, and I'll probably add support for displaying the /arguments/ to certain commands (such as vim), or an alert color for some commands (sudo). > Like I said, though - even though this should take no effort > whatsoever to do with zsh - no more than 5 lines or so - it would be > difficult to maintain compatibility with bash. Eh, I've managed pretty well so far. Where I can't rely on common syntax, I can test for the shell (as you can see by my spamming of the shell namespace with vars like PJOBS_ZSH). I'm aiming for compliance with as many shells will provide me with a hook to the prompt, and are reasonably POSIX-compliant. > The best way I can think of to do what you want, off the top of my > head, is the following: <solution snipped> That'll make a great reference. I'll need to complicate it a bit what with my use of terminal escape sequences (tput output) and whatnot, but that makes a great start. > Frankly, I'd just make your script check for ZSH right off the bat and > do it the simple way, leaving the complicated stuff for shells that > don't give you an elegant solution. Yeah, I'm already doing that (it's just that the zsh-specific solution doesn't work). I already have to cater specifically to bash (PROMPT_COMMAND), and even the set of shells that will let me hook in via prompt substitution each have their unique ways of telling the line-editor to ignore the invisible terminal escape sequences I use for coloring. Thanks very much for the help. For some reason, I simply couldn't find precmd or the job* vars on my own. -- Micah J. Cowan Programmer, musician, typesetting enthusiast, gamer... http://micah.cowan.name/ ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2007-03-08 21:52 UTC | newest] Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-03-08 19:27 "jobs" command within substitution Micah Cowan [not found] ` <17393e3e0703081155o7a240628t49fae220ac9f49ae@mail.gmail.com> [not found] ` <45F070A9.5060502@cowan.name> 2007-03-08 21:19 ` Matt Wozniski 2007-03-08 22:00 ` Micah Cowan
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/zsh/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).