How to pass command line arguments to Deno? - command-line-arguments

I have a Deno app, that I wish to pass some command line args to. I searched the manual, but found nothing.
I tried to use the same commands used in Node.js, assuming they might be sharing some for the std libraries, but it didn't work as well.
var args = process.argv.slice(2);
// Uncaught ReferenceError: process is not defined
Any suggestions?

You can access arguments by using Deno.args, it will contain an array of the arguments passed to that script.
// deno run args.js one two three
console.log(Deno.args); // ['one, 'two', 'three']
If you want to parse those arguments you can use std/flags, which will parse the arguments similar to minimist
import { parse } from "https://deno.land/std/flags/mod.ts";
console.log(parse(Deno.args))
If you call it with:
deno run args.js -h 1 -w on
You'll get
{ _: [], h: 1, w: "on" }

You can use Deno.args to access the command line arguments in Deno.
To try it create a file test.ts :
console.log(Deno.args);
And run it with deno run test.ts firstArgument secondArgument
It will return you with an array of the passed args:
$ deno run test.ts firstArgument secondArgument
[ "firstArgument", "secondArgument" ]

If you take a stroll through the standard library, you will find a library named flags, which sounds like it could be library for command line parsing. In the README, you will find your answer in the very first line:
const { args } = Deno;
Also, if you look at the Deno Manual, specifically the Examples section, you will find numerous examples of command line example programs that perform argument parsing, for example, a clone of the Unix cat command (which is also included in the First Steps section of the Deno Manual), where you will also find your answer in the first line:
for (let i = 0; i < Deno.args.length; i++)
So, in short: the command line arguments are a property of the global Deno object, which is documented here:
const Deno.args: string[]
Returns the script arguments to the program. If for example we run a program:
deno run --allow-read https://deno.land/std/examples/cat.ts /etc/passwd
Then Deno.args will contain:
[ "/etc/passwd" ]
Note: According to the Manual, all non-web APIs are under the global Deno namespace.

Related

Golang Cobra multiple flags with no value

I'm new to Golang, and i'm trying out my first CLI application, using the Cobra framework.
My plan is to have few commands, with many flags.
These flags, don't have to have a value attached to them, since they can simply be -r to restart the device.
Currently, i have the following working, but i keep thinking, that this cannot be the correct way to do it.
So any help is appreciated.
The logic is currently, that each command, get's a default value attached to it, and then i look for this, in the run command, and triggers my function, once it captures it.
My "working code" looks like below.
My init function, in the command contains the following.
chargerCmd.Flags().StringP("UpdateFirmware", "u", "", "Updeates the firmware of the charger")
chargerCmd.Flags().Lookup("UpdateFirmware").NoOptDefVal = "yes"
chargerCmd.Flags().StringP("reboot", "r", "", "Reboots the charger")
chargerCmd.Flags().Lookup("reboot").NoOptDefVal = "yes"
And the run section looks like this.
Run: func(cmd *cobra.Command, args []string) {
input, _ := cmd.Flags().GetString("UpdateFirmware")
if input == "yes" {
fmt.Println("Updating firmware")
UpdateFirmware(os.Getenv("Test"), os.Getenv("Test2"))
}
input, _ = cmd.Flags().GetString("reboot")
if input == "yes" {
fmt.Println("Rebooting Charger")
}
},
Maybe to make the usage a bit cleaner, as stated in the comment from Burak - you can better differentiate between commands and flags. With cobra you have the root command and sub-commands attached to the root command. Additionaly each command can accept flags.
In your case, charger is the root commands and you want two sub-commands: update_firmware and reboot.
So as an example to reboot the charger, you would execute the command:
$ charger reboot
In the code above, you are trying to define sub-commands as flags, which is possible, but likely not good practice.
Instead, the project should be set-up something like this: https://github.com/hesamchobanlou/stackoverflow/tree/main/74934087
You can then move the UpdateFirmware(...) operation within the respective command definition under cmd/update_firmware.go instead of trying to check each flag variation on the root chargerCmd.
If that does not help, provide some more details on why you think your approach might not be correct?

How to pass arguments / parameters to the npm-script using npmExecuteScripts?

I'm trying to run the npm-script from the Jenkins pipeline via the SAP Project Piper's npmExecuteScripts:
npmExecuteScripts:
runScripts: ["testScript"]
That works! Now, I want to pass some arguments to my script.
According to the Project Piper documentation, there is a property scriptOptions, which cares about passing arguments to the called script:
Options are passed to all runScripts calls separated by a --. ./piper npmExecuteScripts --runScripts ci-e2e --scriptOptions --tag1 will correspond to npm run ci-e2e -- --tag1
Unfortunately, I can't figure out what is the proper syntax for that command.
I've tried several combinations of using scriptOptions, e.g.:
scriptOptions: ["myArg"]
scriptOptions: ["myArg=myVal"]
and many others, but still no desired outcome!
How can I call an npm-script and pass arguments / parameters to the script using the Project Piper's npmExecuteScripts?
To solve the issue, it's important to bear in mind that in contrast to the regular argument-value mapping via the npm_config_-prefix, the SAP Project Piper scriptOptions doesn't perform a mapping and passes an array of argument-value pairs «as is» instead, and then this array can be picked up via process.argv.
The Jenkins pipeline configuration:
npmExecuteScripts:
runScripts: ["testScript"]
scriptOptions: ["arg1=Val1", "arg2=Val2"]
package.json:
"scripts": {
"testScript": "node ./testScript.mjs"
}
The server-side script:
/**
* #param {Array.<String>} args - array of console input arguments to be parsed
*/
const testScript = function testScript(args) {…}
testScript(process.argv.slice(2));
P.S. Just to compare, the regular way to pass an argument's value to the npm-script looks like:
npm run testScript --arg=Val
and the server-side script:
"testScript": "echo \"*** My argument's value: ${npm_config_arg} ***\""
The output:
*** My argument's value: Val ***
The npm-script engine performs an argument-value mapping under the hood by using the npm_config_-prefix.

How to pass "args" while using Intellij IDEA [example list 3.11 in Odersky's Scala book (2nd Ed)]

I basically try to run the example 3.11 in Odersky's book (Programming in Scala). I am using Intellij IDE. While runing the code, the "else" branch got executed.
The screen capture is here:
The source is here in case you need it to try:
package ch3
import scala.io.Source
object l3p11 extends App{
def widthOfLength(s: String) = s.length.toString.length
if (args.length > 0){
val lines = Source.fromFile(args(0)).getLines().toList
val longestLine = lines.reduceLeft(
(a, b) => if (a.length > b.length) a else b
)
val maxWidth = widthOfLength(longestLine)
for (line <- lines){
val numSpaces = maxWidth - widthOfLength(line)
val padding = " " * numSpaces
println(padding + line.length + "|" + line)
}
}
else
Console.err.println("Please enter filename")
}
The reason, I think, is becuase I did not pass args correctly (say here I want to pass the source file l3p11.scala as the args). I tried several option, but have not find a way to pass the args correctly for the code to be executed in the "if" branch. There are two directions in my mind to resolve this problem:
1. Find the right way to pass args in Intellij IDE
Run Scala in commond line, a similar command such as
$ scala l3p11.scala l3p11.scala
should be able to pass the args correctly. But my current setting gives "bash: scala: command not found". I currently use scala REPL to run scala code following the set up given in Odersky's Coursera course on Scala. I think I need to change the set up in orde run scala directly, instead of using "sbt->console" to invoke the scala interpreter like what I am doing now.
Any suggestion on either direction (or other directions that I have not thought of) to resolve the problem is welcome.
Update 1:
Direction 2 works after I reinstall scala. (My to be corrected understanding is that the installation of sbt does not provide an executable binary of scala to be included in the environment list for Windows. Therefore, scala command cannot be found before). After installation of scala directly:
$ scala l3p11.scala l3p11.scala
gives the expected results. But I still have not figured out how to get this result with Intellij IDEA.
Update 2:
I revisited the "Program arguments" option after Joe's confirmation. The reason I was not be able to get it work before was that I only add "l3p11.scala". Adding the complete path from working directory "src/main/scala/ch3/l3p11.scala" solved the problem. The result is as following:
To pass command-line arguments when running a program in IntelliJ IDEA, use the "Edit Configurations …" menu item under "Run". Choose the entry for your main program. There's a "Program arguments" text field where you specify the arguments to pass to the program.
I'm not super familiar on how it will run on windows but if you are able to run it directly from the command line then I think you'll need to compile first, that's the scalac command. So:
$ scalac l3p11.scala
then you can run just with the class name, not sure if you would need quotes on the arg:
$ scala l3p11 l3p11.scala

Why does argparse fail to recognise an argument when a Python script is called directly?

I have a simple script like this (based on the docs for argparse):
def Main():
parser = argparse.ArgumentParser()
parser.add_argument("issuenumber", help="Create a local branch based on the specified issue number", type=int)
args = parser.parse_args()
if args.issuenumber:
print("Starting work on issue #"+str(args.issuenumber))
if __name__ == "__main__":
Main()
When I run it however, it never recognises the argument I'm passing it:
C:\Projects\PyTools>Gritter.py 1
usage: Gritter.py [-h] issuenumber
Gritter.py: error: the following arguments are required: issuenumber
If I call the script via a python call it works however:
C:\Projects\PyTools>python Gritter.py 1
Starting work on issue #1
If I print out sys.argv I get:
C:\Projects\PyTools>Gritter 1
['C:\\Projects\\PyTools\\Gritter.py']
C:\Projects\PyTools>Python Gritter.py 1
['Gritter.py', '1']
So I guess something is not passing on the arguments when the script is called directly. I wonder if there's anything that can be done so that the script can be called directly?
The C\ indicates you are using Windows. You have take extra effort to ensure that this 'direct call' passes arguments through to python.
Looking up windows shebang I find, from Python docs that you need to use
#!/usr/bin/python -v
to pass arguments
See https://docs.python.org/3/using/windows.html
argparse uses sys.argv. If that only has the script name then the call isn't passing arguments.
Based on mckoss` answer, I modified the following registry key:
HKEY_CLASSES_ROOT\Applications\python.exe\shell\open\command
From this:
"C:\Python34\python.exe" "%1"
To this:
"C:\Python34\python.exe" "%1" %*
And now my script works as I'd previously expected.

Process name missing from GetCommandLine()

I have a problem with the GetCommandLine() API.
It usually returns the executable name followed by a space and arguments. As documentation says, the first token may not have the complete path to the image and blah blah blah.
I never had problems until now that I used CreateProcess with lpApplicationName not NULL.
If I use:
CreateProcess(NULL, "\"c:\\myexe.exe\" param1 param2", ...)
GetCommandLine returns "c:\myexe.exe param1 param2" as expected.
But if I use:
CreateProcess("C:\myexe.exe", "param1 param2")
GetCommandLine returns only "param1 param2".
How do I know if the executable name is given on the command line if another application launches mine?
Also, MFC startup code assumes that the first token on the command line is the executable name and skips it. But if you launch a MFC application with the second CreateProcess API example, MFC's code will skip the first argument.
Not your problem. It's the job of the other application to construct the command line properly. You should simply assume that the first argument is an executable name as expected and skip over it.
I have a workaround which can be helpful in a case like this.
I guess we always be able to check how our module was been started.
In this case we should check first argument.
I will write code because I have some problem with English.
Here two ways:
The first case. we can compare module name with first command line argument.
something like this:
const TCHAR* csCommandLine = ::GetCommandLine();
// Attention!!! the first symbol can be quete
if (*csCommandLine == _T('\"'))
csCommandLine++;
TCHAR sModuleFileName[MAX_PATH];
DWORD dwModuleFileName = ::GetModuleFileName(NULL, sModuleFileName, MAX_PATH);
if (dwModuleFileName && !_tcsncmp(csCommandLine, sModuleFileName, dwModuleFileName)) {
// The command line contains the module name.
}
The second case. we can try to get file attributes for the first command line argument
something like this:
// Attention!!! don't use it case if you are going to pass a file path in command line arguments.
int nArgc;
LPTSTR* szArglist = ::CommandLineToArgvW(::GetCommandLine(), &nArgc);
if (nArgc && ::GetFileAttributes(szArglist[0]) != INVALID_FILE_ATTRIBUTES) {
// The command line contains the module name.
}
::LocalFree(szArglist);
I hope it can be helpful someone.
Regards, Vladimir

Resources