I'm developing a wrapper around some LiveCode server-side scripts. Is there a way to exit a LiveCode script and specify an exit code? Right now, even unparseable code is given an exit code of 0. I'm looking for something like the exit to top control structure that will let me pass 0-255.
Here's a particularly painful example
$ cat test.lc
> #!/usr/bin/env livecode-community-server
lakjreakl j3lkj4?KJ !$()U* #$)LFKDJ SKLmvnkl 32498*$#
lkfj KJ# >J$? !*!$ kljflkjuia o1238
$ ./test.lc
> file "/home/ian/test.lc"
row 2, col 11: Expression: bad factor (!)
row 2, col 1: param: bad expression
row 2, col 11: Commands: bad parameter (!)
row 2, col 11: Commands: bad parameters (!)
row 2, col 11: script: bad command (!)
$ echo $?
> 0
You are looking for the quit command and its as yet undocumented exit code parameter which defaults to 0!
quit 1
You could try the "return" statement. It exits the current handler and whatever follows is sent to the calling handler. I haven't tried it on server but I'm thinking it might go to stdout if there is no calling handler: return "104"
"put" without a destination always goes to stdout, so you could alternately use "put 104" followed immediately by an "exit to top".
Related
i have process that generates a value. I want to forward this value into an value output channel. but i can not seem to get it working in one "go" - i'll always have to generate a file to the output and then define a new channel from the first:
process calculate{
input:
file div from json_ch.collect()
path "metadata.csv" from meta_ch
output:
file "dir/file.txt" into inter_ch
script:
"""
echo ${div} > alljsons.txt
mkdir dir
python3 $baseDir/scripts/calculate.py alljsons.txt metadata.csv dir/
"""
}
ch = inter_ch.map{file(it).text}
ch.view()
how do I fix this?
thanks!
best, t.
If your script performs a non-trivial calculation, writing the result to a file like you've done is absolutely fine - there's nothing really wrong with this approach. However, since the 'inter_ch' channel already emits files (or paths), you could simple use:
ch = inter_ch.map { it.text }
It's not entirely clear what the objective is here. If the desire is to reduce the number of channels created, consider instead switching to the new DSL 2. This won't let you avoid writing your calculated result to a file, but it might mean you can avoid an intermediary channel, potentially.
On the other hand, if your Python script actually does something rather trivial and can be refactored away, it might be possible to assign a (global) variable (below the script: keyword) such that it can be referenced in your output declaration, like the line x = ... in the example below:
Valid output
values
are value literals, input value identifiers, variables accessible in
the process scope and value expressions. For example:
process foo {
input:
file fasta from 'dummy'
output:
val x into var_channel
val 'BB11' into str_channel
val "${fasta.baseName}.out" into exp_channel
script:
x = fasta.name
"""
cat $x > file
"""
}
Other than that, your options are limited. You might have considered using the env output qualifier, but this just adds some syntactic-sugar to your shell script at runtime, such that an output file is still created:
Contents of test.nf:
process test {
output:
env myval into out_ch
script:
'''
myval=$(calc.py)
'''
}
out_ch.view()
Contents of bin/calc.py (chmod +x):
#!/usr/bin/env python
print('foobarbaz')
Run with:
$ nextflow run test.nf
N E X T F L O W ~ version 21.04.3
Launching `test.nf` [magical_bassi] - revision: ba61633d9d
executor > local (1)
[bf/48815a] process > test [100%] 1 of 1 ✔
foobarbaz
$ cat work/bf/48815aeefecdac110ef464928f0471/.command.sh
#!/bin/bash -ue
myval=$(calc.py)
# capture process environment
set +u
echo myval=$myval > .command.env
I am trying to make a simple feedback loop in my nextflow script. I am getting a weird error message that I do not know how to debug. My attempt is modeled after the NextFlow design pattern described here. I need a value to be calculated from a python3 script that operates on an image but pass that value on to subsequent executions of the script. At this stage I just want to get the structure right by adding numbers but I cannot get that to work yet.
my script
feedback_ch = Channel.create()
input_ch = Channel.from(feedback_ch)
process test {
echo true
input:
val chan_a from Channel.from(1,2,3)
val feedback_val from input_ch
output:
stdout output_val into feedback_ch
shell:
'''
#!/usr/bin/python3
new_val = !{chan_a} + !{feedback_val}
print(new_val)
'''
}
The error message I get
Error executing process > 'test (1)'
Caused by:
Process `test (1)` terminated with an error exit status (1)
Command executed:
#!/usr/bin/python3
new_val = 1 + DataflowQueue(queue=[])
print(new_val)
Command exit status:
1
Command output:
(empty)
Command error:
Traceback (most recent call last):
File ".command.sh", line 3, in <module>
new_val = 1 + DataflowQueue(queue=[])
NameError: name 'DataflowQueue' is not defined
Work dir:
executor > local (1)
[cd/67768e] process > test (1) [100%] 1 of 1, failed: 1 ✘
Error executing process > 'test (1)'
Caused by:
Process `test (1)` terminated with an error exit status (1)
Command executed:
#!/usr/bin/python3
new_val = 1 + DataflowQueue(queue=[])
print(new_val)
Command exit status:
1
Command output:
(empty)
Command error:
Traceback (most recent call last):
File ".command.sh", line 3, in <module>
new_val = 1 + DataflowQueue(queue=[])
NameError: name 'DataflowQueue' is not defined
Work dir:
/home/cv_proj/work/cd/67768e706f50d7675ae93645a0ce6e
Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run`
Anyone have any ideas?
The problem you have says, that you are passing empty DataflowQueue object with input_ch. Nextflow tries to execute it, so it substitutes your python code with variables, resulting in:
#!/usr/bin/python3
new_val = 1 + DataflowQueue(queue=[])
print(new_val)
What is nonsense (You want some number instead of DataflowQueue(queue=[]), don't you?).
Second problem is, that you don't have channels mixed, what seems to be important in this pattern. Anyway, I fixed it, to have proof of concept, working solution:
condition = { it.trim().toInteger() > 10 } // As your output is stdout, you need to trim() to get rid of newline. Then cast to Integer to compare.
feedback_ch = Channel.create()
input_ch = Channel.from(1,2,3).mix( feedback_ch.until(condition) ) // Mixing channel, so we have feedback
process test {
input:
val chan_a from input_ch
output:
stdout output_val into feedback_ch
shell:
var output_val_trimmed = chan_a.toString().trim()
// I am using double quotes, so nextflow interpolates variable above.
"""
#!/usr/bin/python3
new_val = ${output_val_trimmed} + ${output_val_trimmed}
print(new_val)
"""
}
I hope, that it at least set you on right track :)
I would like to run two Python 3 scripts from SPSS syntax window. It is possible to perform it using BEGIN PROGRAM-END PROGRAM. block or SCRIPT command. This time I need to find a solution using second command.
Simplified code:
*** MACROS.
define export_tabs (!positional !tokens (1))
output modify
/select logs headings texts warnings pagetitles outlineheaders notes
/deleteobject delete = yes.
OUTPUT EXPORT
/CONTENTS EXPORT = visible LAYERS = printsetting MODELVIEWS = printsetting
/XLSX DOCUMENTFILE = "doc.xlsx"
OPERATION = createsheet
sheet = !quote(!unquote(!1))
LOCATION = lastcolumn NOTESCAPTIONS = no
!enddefine.
define matrix_tab (!positional !charend('/')
/!positional !charend('/')
/!positional !charend('/')
/!positional !charend('/')
/stat = !tokens (1))
!do !i !in (!3)
ctables
/mrsets countduplicates = no
/vlabels variables = !concat(!1,_,!2,_,!i) display = label
/table !concat(!1,_,!2,_,!i)
[rowpct.responses.count !concat(!unquote(!stat),"40.0"), totals[count f40.0]]
/slabels position = column visible = no
/clabels rowlabels = opposite
/categories variables = !concat(!1,_,!2,_,!i) order = a key = value
empty = include total = yes label = "VALID COUNT" position = after
/titles title = !upcase(!4).
!doend
!enddefine.
*** REPORT.
* Sheet 1.
output close all.
matrix_tab $Q1 / 1 / 1 2 / "QUESTION 1" / stat="pct".
script "C:\path\script 1.py".
script "C:\path\script 2.py".
export_tabs "Q1".
* Sheet 2.
output close all.
matrix_tab $Q2 / 2 / 3 4 / "QUESTION 2" / stat="pct".
script "C:\path\script 1.py".
script "C:\path\script 2.py".
export_tabs "Q2".
When I run a block for the first sheet everything works fine. However, when I run a block for the second sheet SPSS doesn't execute Python scripts and jumps straight to export_tabs macro (problems with synchronization?). I thought a problem had been possibly in a way I executed SCRIPT command. So I tried this:
script "C:\path\script 1.py" pythonversion = 3.
script "C:\path\script 2.py" pythonversion = 3.
but in effect SPSS - even though the syntax window coloured these parts of syntax - returned this error message:
>Error # 3251 in column 152. Text: pythonversion
>The SCRIPT command contains unrecognized text following the the file
>specification. The optional parameter must be a quoted string enclosed in
>parentheses.
>Execution of this command stops.
Has anyone of you had such problem and/or have an idea why this happens?
NOTE: Both Python scripts run smoothly from the Python 3.4.3 shell installed with the version of SPSS I have, thus I don't think the core of the problem is within those codes.
This seems to be a document defect in the way this keyword was implemented. I have been able to replicate it and have logged a defect with IBM SPSS Statistics Development.
In this case, the order matters. Rather than this:
script "C:\path\script 2.py" pythonversion = 3.
Try instead:
script pythonversion = 3 "C:\path\script 2.py".
I want to create a file that prints the number of proxies that I create using a script I have.
This is what I have but for some reason its not giving me the output I want.
echo "How many proxies will you like to create?"
read userInput
for (( portid=10000; portid<=$userInput; portid++ ))
do
echo 42.56.35.1:$portid:test:run
done
Lets say after I answer the question:
How many proxies will you like to create?
and I reply
5
Then I want my output to be:
42.56.35.1:100001:test:run
42.56.35.1:100002:test:run
42.56.35.1:100003:test:run
42.56.35.1:100004:test:run
42.56.35.1:100005:test:run
I want the numbers to continue from 10000 and so on but depending on how many proxies i tell it to make.
Your problem is that you're telling the loop to end when portid is more than 5 (or whatever value the user entered) -- but you're initializing it at 10000, so unless the user requested a very large range, it's always more than 5.
One easy approach is to loop starting at 1, and apply the offset inside the loop:
for (( portid=1; portid<=userInput; portid++ ))
do
echo "42.56.35.1:$(( portid + 10000 )):test:run"
done
Another is to apply the increment on both ends:
for (( portid=10001; portid<=(userInput + 10000); portid++ ))
do
echo "42.56.35.1:$portid:test:run"
done
I have the following function that works fine as long as I give it a valid command to execute. As soon as I give it a non-existent command, the script is interrupted with an error message.
#!/usr/bin/lua
function exec_com(com)
local ok,res=pcall(function() return io.popen(com) end)
if ok then
local tmp=res:read('*a')
res:close()
return ok,tmp
else
return ok,res
end
end
local st,val=exec_com('uptime')
print('Executed "uptime" with status:'..tostring(st)..' and value:'..val)
st,val=exec_com('zzzz')
print('Executed "zzzz" with status:'..tostring(st)..' and value:'..val)
When I run the script above I get the following output:
Executed "uptime" with status:true and value: 18:07:38 up 1 day, 23:00, 3 users, load average: 0.37, 0.20, 0.20
sh: zzzz: command not found
Executed "zzzz" with status:true and value:
You can clearly see above that pcall() function still reported success when executing "zzzz" which is odd.
Can someone help me devise a way to catch an exception when executing a non-existent or ill-formed Linux command using Lua script? Thanks.
Edit: Restated my request after getting the clarification that pcall() works as expected, and the problem is due to popen() failing to throw an error.
I use a method which is similar to your "temporary workaround" but which gives you more information:
local cmd = "uptime"
local f = io.popen(cmd .. " 2>&1 || echo ::ERROR::", "r")
local text = f:read "*a"
if text:find "::ERROR::" then
-- something went wrong
print("error: " .. text)
else
-- all is fine!!
print(text)
end
If you look at io.popen(), you'll see that it'll always return a file handle.
Starts program prog in a separated process and returns a file handle
that you can use to read data from this program (if mode is "r", the
default) or to write data to this program (if mode is "w").
Since, a file handle returned is still a valid value for lua, the pcall(), your local function inside the pcall is returning a true value (and an error is not being propagated); thereby, giving you a true status and no output.
I have come up with my own temporary workaround that pipes the error to /dev/null and determines the success/failure of executed command based on the text received from io.popen():read('*a') command.
Here is my new code:
#!/usr/bin/lua
function exec_com(com)
local res=io.popen(com..' 2>/dev/null')
local tmp=res:read('*a')
res:close()
if string.len(tmp)>0 then
return true,tmp
else
return false,'Error executing command: '..com
end
end
local st,val=exec_com('uptime')
print('Executed "uptime" with status:'..tostring(st)..' and value:'..val)
st,val=exec_com('cat /etc/shadow')
print('Executed "cat /etc/shadow" with status:'..tostring(st)..' and value:'..val)
And the corresponding output is now correct:
Executed "uptime" with status:true and value: 00:10:11 up 2 days, 5:02, 3 users, load average: 0.01, 0.05, 0.19
Executed "cat /etc/shadow" with status:false and value:Error executing command: cat /etc/shadow
In my example above I am creating a "generic" error description. This is an intermediate fix and I am still interested in seeing alternative solutions that can return a more meaningful error message describing why the command failed to execute.
Rather than taking the time reading the whole file into a variable, why not just check if the file is empty with f:read(0)?
Local f = io.popen("NotExist")
if not f:read(0) Then
for l in st:lines() do
print(l)
end
else
error("Command Does Not Exist")
end
From the lua Manual:
As a special case, io.read(0) works as a test for end of file: It returns an empty string if there is more to be read or nil otherwise.