execvp does not get argument - arguments

My code is:
execvp(command, args);
args is char* args[]
command is char* command
for example for ls -l, command is ls and args is -l but why after executing
execvp(command, args)I get only result of ls not ls -l??

The argument list also contains the name of the program. Make sure that your args array contains both "ls" and "-l".

Related

How to specify "usage" for cli arguments (not flags)

For flags I can specify description which appers in --help command
flag.String("a", "", "Is is a flag")
But I don't have flags, only arguments, I use cli like this
mycommand start 4
Is it possible use --help to see description to "start" (and other) arguments?
Since this is not directly supported by flags, I know only of alecthomas/kong which does include argument usage:
package main
import "github.com/alecthomas/kong"
var CLI struct {
Rm struct {
Force bool `help:"Force removal."`
Recursive bool `help:"Recursively remove files."`
Paths []string `arg:"" name:"path" help:"Paths to remove." type:"path"`
} `cmd:"" help:"Remove files."`
Ls struct {
Paths []string `arg:"" optional:"" name:"path" help:"Paths to list." type:"path"`
} `cmd:"" help:"List paths."`
}
func main() {
ctx := kong.Parse(&CLI)
switch ctx.Command() {
case "rm <path>":
case "ls":
default:
panic(ctx.Command())
}
}
You will get with shell --help rm:
$ shell --help rm
usage: shell rm <paths> ...
Remove files.
Arguments:
<paths> ... Paths to remove. <====== "usage" for cli arguments (not flags)!
Flags:
--debug Debug mode.
-f, --force Force removal.
-r, --recursive Recursively remove files.

In bash, how to pass an optional argument with the current dir as default?

I am trying to define my customized cp function, which is something like
mycp() {
cp -r "$1" "${2:$PWD}"
}
where the second argument is optional and should be the current path by default. However, when I run that it always returns an error of "No such file or directory: ''" when there is no 2nd argument, and bash: 2: <mypath> : syntax error: operand expected (error token is "<mypath>") argument when I passed . as 2nd argument.
What did I miss here?
You can do the following (the main thing missing was the - in :- from "${2:-$PWD}":
mycp() {
cp -r "$1" "${2:-$PWD}"
}

How to create a command line pipe? (xcode mac os x)

How to create a command line pipe? (xcode mac os x) Hello I want to
create a command line with xcode (mac os x) that had the quality of
being used in pipe after "|" .
i know that by using xargs we can pass arguments stored in stdin into
arguments.
I would like to understand how to create a pipable command line. Thank
you for your answers
For example, if we define the hand function that should receive the
arguments to execute. In a rudimentary way we will write (in C):
int main (int argc, char ** argv)
{
char buf [512] = "";
char buf1[512] = "";
int f;
and achieve some things
the first argument of the argument array, contains in any case the no
of the command line that you are creating ex: argv [0] "echo" and the
argument following the one you wish to use, 'here for echo argv [1]
"the sun shines" of course if echo is able to receive an argument
after "|" (pipe) for example: echo "the sun is shining" | echo, but
echo do not use the pipe.
For our main function, is elementarily we will check if argv [1]
contains an argument by
if (argv [1] == NULL)
> {
there we arbitrarily take the guess that argv [1] is empty. as a reminder our command line is located after a pipe "|" if our argv [1]
is empty, it will need to find an argument to continue using our
command line, for this we accept the postulate that if the command
line is placed after "|" pipe is that the output of the previous
command is not empty from where what will follow
> f = open ("/ dev / stdin", O_RDONLY);
> read (f, buf, sizeof (buf));
memcpy (buf1, buf, sizeof (buf));
now we have opened the stream "stdin" which necessarily contains the
output of the previous command, we use 2 buffers buf [512] and buf1
[512], because we can not fill argv [1], now that we have our
arguments in a buffer, one can realize the continuation of the
execution of the command, as if it were about argv [1].
In objective-c or in C simply, to give an line command the virtue to
be used ien pipeline as a result of the use of "|" after another
command line, it is necessary to redirect "stdin" towards the entry of
the command line as it was an argument ("argv"). From there by
mastering a little programming in "C", one must arrive at its ends to
make a command line create with xcode, usable after "|" .

How to pass arguments to a jshell script?

Question
I am willing to pass arguments to a jshell script. For instance, I would have liked something like this:
jshell myscript.jsh "some text"
and then to have the string "some text" available in some variable inside the script.
However, jshell only expects a list of files, therefore the answer is:
File 'some text' for 'jshell' is not found.
Is there any way to properly pass arguments to a jshell script?
Workaround so far
My only solution so far is to use an environment variable when calling the script:
ARG="some test" jshell myscript.jsh
And then I can access it in the script with:
System.getenv().get("ARG")
And what about option -R
> jshell -v -R-Da=b ./file.jsh
for script
{
String value = System.getProperty("a");
System.out.println("a="+value);
}
/exit
will give you
> jshell -v -R-Da=b ./file.jsh
a=b
Another way, would be following:
{
class A {
public void main(String args[])
{
for(String arg : args) {
System.out.println(arg);
}
}
}
new A().main(System.getProperty("args").split(" "));
}
and execution
> jshell -R-Dargs="aaa bbb ccc" ./file_2.jsh
Update
Previous solution will fail with more complex args. E.g. 'This is my arg'.
But we can benefit from ant and it's CommandLine class
import org.apache.tools.ant.types.Commandline;
{
class A {
public void main(String args[])
{
for(String arg : args) {
System.out.println(arg);
}
}
}
new A().main(Commandline.translateCommandline(System.getProperty("args")));
}
and then, we can call it like this:
jshell --class-path ./ant.jar -R-Dargs="aaa 'Some args with spaces' bbb ccc" ./file_2.jsh
aaa
Some args with spaces
bbb
ccc
Of course, ant.jar must be in the path that is passed via --class-path
Oracle really screwed this up, there is no good way to do this. In addition to #mko's answer and if you use Linux(probably will work on Mac too) you can use process substitution.
jshell <(echo 'String arg="some text"') myscript.jsh
And then you can just use arg in myscript.jsh for example:
System.out.println(arg) // will print "some text"
You can simplify it with some bash function and probably write a batch file that will write to a temp file and do the same on windows.
It's completely beyond me how Oracle could ignore this. 8-() But anyway: if your system uses bash as shell, you can combine this approach replacing the shebang with the idea to (ab-)use system properties to transport the whole command line into a variable:
//usr/bin/env jshell --execution local "-J-Da=$*" "$0"; exit $?
String commandline = System.getProperty("a");
System.out.println(commandline);
/exit
This way, you can call the script on the commandline simply adding the arguments: thisscript.jsh arg1 arg2 would print arg1 arg2.
Please note that this joins all parameters into one String, separated by one space. You can split it again with commandline.split("\s"), but please be aware that this isn't exact: there is no difference between two parameters a b and one parameter "a b".
If you have a fixed number of arguments, you can also pass all of these into separate system properties with "-J-Darg1=$1" "-J-Darg2=$1" "-J-Darg3=$1" etc. Please observe that you have to use -R-D... if you are not using --execution local
Another variant is generating the script on the fly with bash's process substitution. You can use such a script also simply as thisscript.jsh arg1 arg2 also on Unix-like systems having a bash.
#!/usr/bin/env bash
jshell <(
cat <<EOF
System.out.println("$1");
System.out.println("$2");
/exit
EOF
)
This allows to access individual parameters, though it will break when there are double quotes or other special characters in a parameter. Expanding on that idea: here's a way to put all parameters into an Java String array, quoting some of those characters:
#!/usr/bin/env bash
set -- "${#//\\/\\\\}"
set -- "${#//\"/\\\"}"
set -- "${#/#/\"}"
set -- "${#/%/\",}"
jshell <(
cat <<EOF
String[] args = new String[]{$#};
System.out.println(Arrays.asList(args));
/exit
EOF
)
The set -- statements double backslashes, quote double quotes and prefix a " and append a ", to transform the arguments into a valid Java array.
Recently, I was inspired by answers from Oleg and Hans-Peter Störr enough to try to combine them so that a) I could use normal shell arguments b) write regular Java code expecting a String[] args input:
//usr/bin/env jshell <(ARGS=; for var in "$#"; do ARGS+="\"$var\","; done; echo "String[] args = {$ARGS}") "$0"; exit $?
System.out.println("RESULT: " + Arrays.asList(args));
/exit
Using Hans' header line and then inlining as demonstrated by Oleg which builds the $# args into a String[] args var.
With that you can chmod +x your script and execute it with regular old arguments:
]$ ./script.jsh foo bar
RESULT: [test, bar]

How can I log STDOUT and STDERR to a single file and show only STDERR in the console using Ruby?

I can do something like this in bash:
myCommand arg1 arg2 2>&1 >> myLogFolder/myLogFile.log | tee -a myLogFolder/myLogFile.log
I would like to be able to say this instead:
log.rb myLogFolder/myLogFile.log myCommand arg1 arg2
Using the log.rb script would accomplish two things:
Result in a simpler statement with less redirection tricks and only a single specification of the log file.
Create the log folder, if necessary.
I was looking at Ruby's popen and spawn options, but I don't see a way to split the STDERR stream to two destinations.
This Ruby script satisfies my needs, but maybe there is a better way.
logPath = ARGV[0]
logFolder = File.dirname(logPath)
command = ARGV.slice(1..-1).join(" ")
`mkdir -p #{logFolder}`
exec "#{command} 2>&1 >> #{logPath} | tee -a #{logPath}"
Try this article about implementing functionality similar to tee using Ruby. You should be able to use that as a starting point for a pure-ruby (or at least exec-free) implementation of your shell code.
You can use Open3 module (manual) It returns 3 objects: stdin, stdout, stderr
However, you are not able to preserve the order between stdout and stderr.
Example:
#include <stdio.h>
int main(int argc, char *argv[]) {
fprintf(stdout, "Normal output\n");
fprintf(stderr, "Error output\n");
fprintf(stdout, "Normal output\n");
}
It is captured as:
Normal output
Normal output
Error output
The only way how to preserve order is to run program twice. :-(
Sample ruby code:
#!/usr/bin/env ruby
require 'open3'
require 'pathname'
logfile = ARGV.first()
cmd = ARGV.drop(1).join(" ")
dir = Pathname(logfile).dirname
if not File.directory?(dir)
Dir.mkdir(dir)
end
file = File.open(logfile, "w")
stdin, stdout, stderr = Open3.popen3(cmd)
stdin.close()
file.puts(stdout.read())
error = stderr.read()
file.puts(error)
puts error
file.close

Resources