2

Directly to the point, I want to give the user the flexibility to pass arguments to a command in order to control how the commands should run, something like:

pcap -d 30 -w 2

In other words:

I want to make a command that looks exactly like Linux commands. A command that works exactly as Linux commands. A command that has options (i.e.: arguments) in the same style as Linux commands.

I want to create a command that works by taking arguments from the user or by using its default arguments (read from a configuration file) in case no arguments are supplied by the user, exactly like any other Linux commands.

A command with --help that shows the different options.

I know how to make a command in Linux. But I don't know how to make these options (command arguments). I don't know how these arguments are programmed.

a guide, a tutorial or an example will do

Note:

  1. Apologies if this question is asked in the wrong stack.
  2. Also apologies for the previous version of the question, it was badly phrased.
Jacob Vlijm
  • 83,767
McLan
  • 251
  • 1
  • 7
  • 16
  • Would you prefer a python answer? – Jacob Vlijm Jun 01 '16 at 11:13
  • @JacobVlijm : yes please .. I am open to any solution – McLan Jun 01 '16 at 11:23
  • "I want to be able to create a command with a configuration file. So that the user enter the answers for the questions above as options in the command line itself." I don't see how these two requirements line up. Do you want defaults to specified in a config file, and optionally overriden by command-line arguments? In any case, this is just generic programming and should be asked on [so]. – muru Jun 01 '16 at 12:08
  • You are right, it is a little bit confusing. I want to have the default values specified in the config file, and overridden (or give more precision to the output) by command line argument. Regards the question: I thought it is related to Ubuntu, my apologies. @muru – McLan Jun 01 '16 at 15:26
  • You still need to clarify the question. Remember this is not a helpdesk; answers and questions should be clear about what they mean to say, to be useful for others. The question as it is gives no information to edit the answer(s) into something that seems to be acceptable to you. – Jacob Vlijm Jun 02 '16 at 05:20
  • Thank you for pointing out that this forum is not a helpdesk. However, I am not asking for a service nor asking for someone to write me a working solution. I am asking for help as how should I do something. I am asking for guidance from those who have better knoweldge than me, as yourself. If my question is not clear, then accept my apologies for not being a native english speaker and my english is limited by the volcabury I learned so far. I will try to explain my question more clearly as to be useful for others @JacobVlijm – McLan Jun 02 '16 at 09:40
  • 1
    @Suda.nese thanks, I'd appreciate that. (of course) no appoligies needed (at all) on the language. There are people from numerous origins posting here, that's part of the fun. We need however to create a question and answer combination that fit together. An open end; a question that remains unclear with a set of answers that miss target, that's not in your interest as well. If I can help with that anyhow, please mention. – Jacob Vlijm Jun 02 '16 at 09:49
  • I appreciate your help too and your consideration. Please check the update. Hope it is better now. @JacobVlijm – McLan Jun 02 '16 at 09:59
  • Thanks a lot, but what I am confused about is that this is exactly what my answer does, or is it the format of the arguments. That is fixed in a jiffy, anything is possible. Have to run, will be back in a few hours, but I am curious to your opinion. – Jacob Vlijm Jun 02 '16 at 10:02
  • In your answer I have to run the python script (ending with .py) with the arguments. But I need to run a command (not a file ending with .py which need the keyword python to run). Then, the arguments has to be passed to the command to override the default (just as you did it in your python example). But, yes, the format of the arguments in your answer are different from those in Linux. Most files I found in the internet are c files something like this. @JacobVlijm – McLan Jun 02 '16 at 11:53
  • @Suda.nese updated my answer. Please see if this is what you are looking for. – Jacob Vlijm Jun 02 '16 at 18:15

3 Answers3

3

Since you mention python, a python answer:

if you simply want to set a default value for an argument, you can simply set the default for the function:

def show(val = 30):
    print(val)
# to print the default value (30)
show()
# to show another value (e.g. 40)
show(40)

In other words, this will print the default value if you give no argument, while it uses the argument if you give it.

More advanced; reading the default values from a file, with the option to overrule by giving the arguments

The very same can be done, but reading default arguments from a file. This will give the opportunity to set arguments in a settings file instead of editing them in the code itself.

Let's say I have a settings file, testconf.txt:

length:4
height:7
width:6

...and I want to read these values into my application as default arguments, but the user can overrule them by custom arguments:

#!/usr/bin/env python3
import sys

# path to my config file
conf_file = "/home/jacob/Bureaublad/testconf.txt"
# read the default arguments from a file
def_args = [l.strip() for l in open(conf_file).readlines()]
# replace default args by possible custom args
cust_args = sys.argv[1:]
for cu in cust_args:
    argname = cu.split(":")[0]
    try:
        match = [arg for arg in def_args if arg.startswith(argname)][0]
    except IndexError:
        print("incorrect argument: ", cu)
    else:
        def_args[def_args.index(match)] = cu

def get_arg(s):
    return [val.split(":")[1] for val in def_args if val.startswith(s)][0]

l = get_arg("length")
w = get_arg("width")
h = get_arg("height")

print("l=", l, "w=", w, "h=", h)

Now I can run the script without arguments:

$ '/home/jacob/Bureaublad/pscript_4.py'
l= 4 w= 6 h= 7

Or width arguments:

$ '/home/jacob/Bureaublad/pscript_4.py' length:10 height:456
l= 10 w= 6 h= 456

The order of given arguments is in this setup irrelevant. In case of an incorrect argument:

$ '/home/jacob/Bureaublad/pscript_4.py' monkey
incorrect argument:  monkey
l= 4 w= 6 h= 7

Note

In "real" software, you can (and should) make it more advanced of course by adding a warning if the settings file is incorrect or missing, decide what to do then, but this is the basic idea.


EDIT

From your comments, I understand that in two ways, the above answer is not (yet) what you are looking for:

  1. You'd like to run the command without the path to the executable (script), and its extension, and
  2. You'd like to have a more "conventional" format of the options.

Although [1] is anwered elsewhere already, I'll include a brief explanation here:

1. Run the command without path and extension

You can run executables and scripts without having to include the path to the script by making it executable (chmod +x <files>), and place them anywhere in $PATH.

On Linux, the extension (.py) does not play a role whatsoever, so you can use the script without extension anyway.

To be concrete:

  • create, if it doesn't exist yet, the directory ~/bin
  • create and save the script, exactly as mentioned in the original answer, as showsize (no extenion) in ~/bin, and make the script executable.

    After a log out/in, you can simply run the script by the command:

    showsize
    

2. Change the format of the options

As mentioned, you can change the format of the options easily, e.g.: To parse out the options, given like:

-l 23 -h 210 -w 321
  • If you include in the script:

    args = sys.argv[1:]

    The result for argswill be a list:

    ["-l", "23", "-h", "210", "-w", "321"]
    

    Now what we need to do to get the value of -h, is simply look up the index of -h, and pick the first next item in the list:

    height = args[args.index("-h")+1]
    print(height)
    
    > 210
    

    in a script:

    #!/usr/bin/env python3
    import sys
    
    # path to my config file
    conf_file = "/home/jacob/Bureaublad/testconf.txt"
    # read the default arguments from a file
    def_args = [l.strip().split(":") for l in open(conf_file).readlines()]
    # replace default args by possible custom args
    cust_args = sys.argv[1:]
    for carg in cust_args:
        if carg in ["-l", "-h", "-w"]:                        
            for d in def_args:
                d[1] = cust_args[cust_args.index(carg)+1] if d[0] == carg else d[1]
    
    def get_arg(s):
        # fetch values from the list
        return [val[1] for val in def_args if val[0] == s][0]
    
    l = get_arg("-l")
    w = get_arg("-w")
    h = get_arg("-h")
    
    print("length =", l, "\nwidth =", w, "\nheight =", h)
    

How to use

  1. Create your settings file in the format:

    -l:4
    -h:7
    -w:6
    
  2. Copy the script into an empty file, svae it as showsize (no extension) in ~/bin or anywhere else in $PATH, and make it executable.

  3. In the head section of the script, set the path to the settings file:

    # path to my config file
    conf_file = "/home/jacob/Bureaublad/testconf.txt"
    

    Now run the command:

    $ showsize
    length = 4 
    width = 6 
    height = 7
    

    Or:

    $ showsize -l 300 -h 345 -w 751
    length = 300 
    width = 751 
    height = 345
    
Jacob Vlijm
  • 83,767
  • 1
    Consider using getopt or argparse instead of writing your own argument parser – muru Jun 01 '16 at 12:16
  • @muru, AHA, nice, have to teach this afternoon, but will look into it. Thanks! – Jacob Vlijm Jun 01 '16 at 12:17
  • It is almost what I need, yet not exactly. Thank you anyway for the answer. I want to write a command script that runs the python code. The user fill the command arguments before it is executed (just like running "ls" command where arguments are in "-l" or "-a" format. While the command is running, the user arguments are passed to the python code which override the default values for these arguments in case they have values, otherwise use the default values. I just want to create look-alike linux commands with options and arguments. @jacobvlijm – McLan Jun 01 '16 at 15:38
  • @Suda.nese that is exactly what the answer is doing. please clarify. – Jacob Vlijm Jun 02 '16 at 05:21
  • @Suda.nese updated my answer. Please see if this is what you are looking for. – Jacob Vlijm Jun 02 '16 at 18:15
2

Script file:

#!/bin/bash

# set default values
X=10
Y="lorem ipsum"

source ~/.myscript.conf

echo "X = $X, Y = $Y"

.myscript.conf file:

X=20
Y="something else"

Now, if a user runs script file and does not have .myscript.conf file in his home directory, script will use X=10 and Y="lorem ipsum", if there is config file, it will use values from the file.

Source command executes contents of the file given as an argument in current shell, so here, it will assign new values to X and Y overwriting defaults from the script file.

Since ~ points to user home directory this setup will work for any user on your system (also root).

[Edit] And in your specific example:

#!/bin/bash
X=10
Y=2
source ~/.config.conf
pcap -d $X -w $Y
  • Thanks for the answer. I already have similar setup. but I need to give the user the possibility to change how to run the command by writing arguments associated to the command "pcap". Just like running any linux command with --help or -- arguments – McLan Jun 01 '16 at 15:42
1

Bash: same as Marek's with sourcing a file with user's values, with the caveat that this file can do anything, and typos will just elicit syntax errors, so this requires a bit of user know-how. You can parse command line parameters with getopts.

Python: see the argparse module to parse command line parameters, and ConfigParser(v2) and configparser(v3) to parse a .ini file.

Typically you use a config file for things that don't change often, and command line parameters for things that are likely different on each run. Editing a config file on each run is a PITA.

xenoid
  • 5,504