User avatar
RaspbianUser1
Posts: 841
Joined: Thu Mar 05, 2020 6:34 pm
Location: ~/

[solved]Reading command inputted

Thu May 06, 2021 7:51 pm

Hi, I am having some issue programming and need some help.

My problem is, I want to read the command inputted E.G. ./a.out hello world

I would to then remove the a.out and just have it print

hello world

so far, the furthest I have got is ./a.outhelloworld

Thanks for any help
Last edited by RaspbianUser1 on Thu May 06, 2021 10:26 pm, edited 1 time in total.
Running with a Raspberry Pi 4B 4GB with Raspberry Pi OS with MATE Desktop
Why not overclock, push some more performance out of your computer!
Think before you delete something a stranger on the internet told you to.

jimbox51
Posts: 41
Joined: Thu Apr 12, 2012 6:57 pm
Location: Wakefield UK

Re: Reading command inputted

Thu May 06, 2021 8:25 pm

RaspbianUser1 wrote:
Thu May 06, 2021 7:51 pm
Hi, I am having some issue programming and need some help.

My problem is, I want to read the command inputted E.G. ./a.out hello world

I would to then remove the a.out and just have it print

hello world

so far, the furthest I have got is ./a.outhelloworld

Thanks for any help
It would be helpfull to show your code.

Try this ref. and the simple program shown there...

https://www.cprogrammingbasics.com/argv-and-argc/

But any simple C tutorial would conver this topic.

User avatar
RaspbianUser1
Posts: 841
Joined: Thu Mar 05, 2020 6:34 pm
Location: ~/

Re: Reading command inputted

Thu May 06, 2021 8:28 pm

Well actually I did get that far, all I need is the ability to put spaces between the words from argv and ignore argc[0] and just print the rest
Running with a Raspberry Pi 4B 4GB with Raspberry Pi OS with MATE Desktop
Why not overclock, push some more performance out of your computer!
Think before you delete something a stranger on the internet told you to.

GlowInTheDark
Posts: 1713
Joined: Sat Nov 09, 2019 12:14 pm

Re: Reading command inputted

Thu May 06, 2021 8:52 pm

Code: Select all

for (int i=1; i<argc; i++)
    printf("%s%s",argv[i],i+1 == argc ? "\n" : " ");
GitD's list of things that are not ready for prime time:
1) IPv6
2) 64 bit OSes
3) USB 3
4) Bluetooth

Loves Linux; loves to dance.

User avatar
manu2007
Posts: 36
Joined: Fri Apr 02, 2021 1:13 pm

Re: Reading command inputted

Thu May 06, 2021 8:56 pm

This should work :

Code: Select all

#include <stdio.h>

int main(int argc, char **argv)
{
    printf("Total number of command Line Agrguments = %d \n", argc);
    
    for (int i = 1; i < argc; ++i)
    {
        printf("i = %d , val = %s\n", i, argv[i]);
    }
    
    return 0;
}

User avatar
RaspbianUser1
Posts: 841
Joined: Thu Mar 05, 2020 6:34 pm
Location: ~/

Re: Reading command inputted

Thu May 06, 2021 8:57 pm

@glowinthedark
wow, that works super well

but I don't know how it works, could you please explain it

all I can gather is the for line starts at 1 to eliminate the first word (or is that wrong :oops: )

Thanks a lot for the code
Running with a Raspberry Pi 4B 4GB with Raspberry Pi OS with MATE Desktop
Why not overclock, push some more performance out of your computer!
Think before you delete something a stranger on the internet told you to.

User avatar
RaspbianUser1
Posts: 841
Joined: Thu Mar 05, 2020 6:34 pm
Location: ~/

Re: Reading command inputted

Thu May 06, 2021 8:59 pm

manu2007 wrote:
Thu May 06, 2021 8:56 pm
This should work :

Code: Select all

#include <stdio.h>

int main(int argc, char **argv)
{
    printf("Total number of command Line Agrguments = %d \n", argc);
    
    for (int i = 1; i < argc; ++i)
    {
        printf("i = %d , val = %s\n", i, argv[i]);
    }
    
    return 0;
}


I had found that code or similar on stack, however it didn't answer my question on how to turn it into a full sentence
Running with a Raspberry Pi 4B 4GB with Raspberry Pi OS with MATE Desktop
Why not overclock, push some more performance out of your computer!
Think before you delete something a stranger on the internet told you to.

GlowInTheDark
Posts: 1713
Joined: Sat Nov 09, 2019 12:14 pm

Re: Reading command inputted

Thu May 06, 2021 9:13 pm

all I can gather is the for line starts at 1 to eliminate the first word (or is that wrong :oops: )
Yeah, argv[0] is the command name, the rest of the args start at argv[1].

And, of course, the other part of the trick is that you print out each arg followed by another string. That "another" string is a space for all but the last arg, and is a newline for the last one (where i is exactly one less than argc).
GitD's list of things that are not ready for prime time:
1) IPv6
2) 64 bit OSes
3) USB 3
4) Bluetooth

Loves Linux; loves to dance.

User avatar
RaspbianUser1
Posts: 841
Joined: Thu Mar 05, 2020 6:34 pm
Location: ~/

Re: Reading command inputted

Thu May 06, 2021 9:23 pm

How can I get this data into a variable?

I haven't done any c in a while an have got really sloppy

I need it in a variable so I can run something like
system(output);
Running with a Raspberry Pi 4B 4GB with Raspberry Pi OS with MATE Desktop
Why not overclock, push some more performance out of your computer!
Think before you delete something a stranger on the internet told you to.

GlowInTheDark
Posts: 1713
Joined: Sat Nov 09, 2019 12:14 pm

Re: Reading command inputted

Thu May 06, 2021 10:10 pm

Well, the obvious answer is: It is already in a variable. The name of the variable is argv.

But, it sounds like what you really need is to concatenate them together into a single string.

One way would be:

Code: Select all

char buff[1000];

*buff = 0;
for (int i=1; i<argc; i++)
    strcat(strcat(buff,argv[i])," ");
buff[strlen(buff) - 1] = '\0';    
Note that this is not as efficient as it could be, but I erred on the side of keeping it as simple as possible.
GitD's list of things that are not ready for prime time:
1) IPv6
2) 64 bit OSes
3) USB 3
4) Bluetooth

Loves Linux; loves to dance.

User avatar
RaspbianUser1
Posts: 841
Joined: Thu Mar 05, 2020 6:34 pm
Location: ~/

Re: Reading command inputted

Thu May 06, 2021 10:21 pm

precisely what I wanted, perfect!

and also compared to that 2 liner before, this is a lot more intuitive
however what does this do

Code: Select all

buff[strlen(buff) - 1] = '\0';
without it the code still works and makes no difference, however I should know what it does incase
Running with a Raspberry Pi 4B 4GB with Raspberry Pi OS with MATE Desktop
Why not overclock, push some more performance out of your computer!
Think before you delete something a stranger on the internet told you to.

User avatar
RaspbianUser1
Posts: 841
Joined: Thu Mar 05, 2020 6:34 pm
Location: ~/

Re: Reading command inputted

Thu May 06, 2021 10:22 pm

Nevermind, I looked at it and realised that it removed the last space
Running with a Raspberry Pi 4B 4GB with Raspberry Pi OS with MATE Desktop
Why not overclock, push some more performance out of your computer!
Think before you delete something a stranger on the internet told you to.

Heater
Posts: 18202
Joined: Tue Jul 17, 2012 3:02 pm

Re: [solved]Reading command inputted

Fri May 07, 2021 5:00 am

Please note that GlowInTheDark's solution is buggy.

Consider what happens when the user inputs long strings. Or a lot of arguments. That for loop will happily fill up the 1000 character buffer and continue past the end of it, writing into memory it should not be writing into.

This is known as "undefined behaviour" in C. Your program is trying to work outside the specification of the C language. These kind of bugs may not show up, you program may just work by chance. They may show up when your program gets bigger and cause you a lot of head scratching. The best outcome would be if they immediately crashed your program. They have been the cause of countless security problems over the decades.

Use of strcat and similar functions, strcpy etc, is not recommended. At least use the length limit versions strncat etc. Or at least add some code to verify that buffer overflow cannot occur.

See: https://c-for-dummies.com/blog/?p=2801
Memory in C++ is a leaky abstraction .

GlowInTheDark
Posts: 1713
Joined: Sat Nov 09, 2019 12:14 pm

Re: [solved]Reading command inputted

Fri May 07, 2021 5:32 am

It's not "buggy". It is, as the comment indicates, not the most efficient (or the most "safe") way to do it, but doing it in full generality is beyond the scope of a posting to a public forum. Adding the code necessary to ensure that the we don't write past the end of the buffer is not particularly difficult, but is beyond the scope.

A "safe" way to do it would be to use C++ and the built-in "string" package.

Or to use my (or anyone else's) "safe string" package - but again, beyond the scope of this posting.

Sheesh!
GitD's list of things that are not ready for prime time:
1) IPv6
2) 64 bit OSes
3) USB 3
4) Bluetooth

Loves Linux; loves to dance.

dsyleixa123
Posts: 1435
Joined: Mon Jun 11, 2018 11:22 am

Re: [solved]Reading command inputted

Fri May 07, 2021 8:59 am

Consider what happens when the user inputs long strings. Or a lot of arguments. That for loop will happily fill up the 1000 character buffer and continue past the end of it, writing into memory it should not be writing into.
safe enough if one donates a ~64k buff size
char buff[65000];
that should fit for general purposes ;-)
Last edited by dsyleixa123 on Fri May 07, 2021 10:57 am, edited 2 times in total.

User avatar
RaspbianUser1
Posts: 841
Joined: Thu Mar 05, 2020 6:34 pm
Location: ~/

Re: [solved]Reading command inputted

Fri May 07, 2021 10:33 am

Does one normally enter commands that long, I think my longest was probably 50 characters
Running with a Raspberry Pi 4B 4GB with Raspberry Pi OS with MATE Desktop
Why not overclock, push some more performance out of your computer!
Think before you delete something a stranger on the internet told you to.

GlowInTheDark
Posts: 1713
Joined: Sat Nov 09, 2019 12:14 pm

Re: [solved]Reading command inputted

Fri May 07, 2021 1:27 pm

In order to see things the way, that one poster (on this very thread) chose to see things, you have to assume a truly malicious user - who knows how big you made the buffer and is willing to type in enough characters to overflow that buffer. The point is that, on this assumption, you can never make it big enough - even if you make it many gigabytes, he (the malicious user) could type in enough to break it. But note also, that in order to actually do any damage, he'd have to know exactly which bytes to type in (what bytes of machine code to put in and exactly where they will land). It's all very theoretical, but I guess it actually has happened once or twice in recorded history. (See: The Morris Worm - c. 1986).

Anyway, here's another way to do it (this time I am giving the full, tested, compilable program; I'm sure this may cause some readers to get a little, shall we say, heated...):

Code: Select all

#include <stdio.h>
#include <assert.h>

int main(int argc, char **argv)
{
    assert(argc > 1);
    for (int i=2; i < argc; i++)
	* (argv[i] - 1) = ' ';
    puts(argv[1]);
}
Also, I forget now what the overall goal of the project was. ISTR that it may have been just to execute the passed args as a sub-process - sort of like the "time" utility does - you pass it a command line and it executes that command line. In that case, you don't really need to concatenate them together at all. You can just pass them as is to one of the exec() functions, like this (after forking if needed):

Code: Select all

argv++;
execvp(*argv,argv);
GitD's list of things that are not ready for prime time:
1) IPv6
2) 64 bit OSes
3) USB 3
4) Bluetooth

Loves Linux; loves to dance.

User avatar
jahboater
Posts: 7035
Joined: Wed Feb 04, 2015 6:38 pm
Location: Wonderful West Dorset

Re: [solved]Reading command inputted

Fri May 07, 2021 2:00 pm

I agree with Heater, get in the habit of coding defensively - the arithmetic is simple enough here.
Also having the lengths available avoids the grossly inefficient repeated strcat and final strlen.

This version is both safe and fast:

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum { BUFSIZE=1000 };

int
main( int argc, const char *argv[] )
{
  char buf[BUFSIZE];
  size_t total_len = 0;
  for( int i = 1; i < argc; ++i )
  {
    const size_t len = strlen(argv[i]);
    if( BUFSIZE - total_len < len + 1 )
    {
      fprintf(stderr, "argument list too long\n");
      exit(EXIT_FAILURE);
    }
    memcpy(buf + total_len, argv[i], len);
    total_len += len;
    buf[total_len++] = ' ';
  }
  buf[total_len] = '\0';

    // use it
  puts(buf);
}

Heater
Posts: 18202
Joined: Tue Jul 17, 2012 3:02 pm

Re: [solved]Reading command inputted

Fri May 07, 2021 3:24 pm

GlowInTheDark wrote:
Fri May 07, 2021 5:32 am
It's not "buggy".
OK. We can be generous. It's not buggy it's "feature full":

Feature 1) It likely crashes when the input is too big.
Feature 2) If it does not crash it likely causes incorrect results in some other part of the program or crates later when doing something else.
Feature 3) The user has no idea when the first 2 features will be triggered.
Feature 4) For the apparently maximum size input you have in mind, 50 characters, it uses 20 times more memory than needed.
GlowInTheDark wrote: doing it in full generality is beyond the scope of a posting to a public forum. Adding the code necessary to ensure that the we don't write past the end of the buffer is not particularly difficult, but is beyond the scope.

I have no idea where that 50 characters came from. That was not part of the requirement. Anyway it's often easily exceeded. Consider for example using something like this:

Code: Select all

./somePprog `ls`
I will agree that one cannot go into too much detail in a mere forum post. However when advising what seems to be a beginner it seems appropriate to indicate the pitfalls of the approach.
GlowInTheDark wrote: Sheesh!
Oh alright. I take it back. That code is buggy.
GlowInTheDark wrote: In order to see things the way, that one poster (on this very thread) chose to see things, you have to assume a truly malicious user - who knows how big you made the buffer and is willing to type in enough characters to overflow that buffer.
It's OK. You can use my name when talking about me.

Anyway that talk of "truly malicious user" is clearly not true. Any user could find it does not work when trying to us it in what they think is a normal way. Failing at random for unknown reasons is generally called a "bug".
GlowInTheDark wrote: The point is that, on this assumption, you can never make it big enough
True. But one can check ones input before processing it. Which is suggested as good practice by most experienced software engineers. One can give useful error messages rather than just crashing.
GlowInTheDark wrote: But note also, that in order to actually do any damage, he'd have to know exactly which bytes to type in (what bytes of machine code to put in and exactly where they will land). It's all very theoretical, but I guess it actually has happened once or twice in recorded history.
This not true on any count.

The bug shows up as a crash, at least, without knowing anything about bytes of machine code or whatever.

Far from theoretical. Such sloppy, unchecked, use of memory, as shown in the example, has been the cause of countless bugs in all kind of software for decades. It has been the root cause of countless security vulnerabilities in all kind of systems. Microsoft has estimated it at 70% of the vulnerabilities in their products: https://msrc-blog.microsoft.com/2019/07 ... cure-code/ Others report similarly.
Memory in C++ is a leaky abstraction .

User avatar
RaspbianUser1
Posts: 841
Joined: Thu Mar 05, 2020 6:34 pm
Location: ~/

Re: [solved]Reading command inputted

Fri May 07, 2021 3:32 pm

While I understand the issue, if someone wants to break their machine, they can do it by opening a terminal and running rm / (not actual command obviously)

This code isn’t being used for anything other than removing the first word then running the rest

Its primary purpose is it to remove the $ at the beginning of guide commands
Running with a Raspberry Pi 4B 4GB with Raspberry Pi OS with MATE Desktop
Why not overclock, push some more performance out of your computer!
Think before you delete something a stranger on the internet told you to.

User avatar
RaspbianUser1
Posts: 841
Joined: Thu Mar 05, 2020 6:34 pm
Location: ~/

Re: [solved]Reading command inputted

Fri May 07, 2021 3:42 pm

I ended up setting the variable as

Code: Select all

char command[4096];
Would you recommend higher?
Running with a Raspberry Pi 4B 4GB with Raspberry Pi OS with MATE Desktop
Why not overclock, push some more performance out of your computer!
Think before you delete something a stranger on the internet told you to.

Heater
Posts: 18202
Joined: Tue Jul 17, 2012 3:02 pm

Re: [solved]Reading command inputted

Fri May 07, 2021 4:59 pm

RaspbianUser1 wrote:
Fri May 07, 2021 3:32 pm
While I understand the issue, if someone wants to break their machine, they can do it by opening a terminal and running rm / (not actual command obviously)
Very true. Feel free to ignore all advice.
RaspbianUser1 wrote: Would you recommend higher?
Impossible to say. Make it as big as your application requires. Only you know that.

I would recommend checking ones inputs, using "strn..." functions instead of the older "str..." versions. And failing gracefully with a meaningful error message. Nothing more that what is commonly recognised as good practice in the C programming and other programming worlds.

It's up to you.
Memory in C++ is a leaky abstraction .

User avatar
RaspbianUser1
Posts: 841
Joined: Thu Mar 05, 2020 6:34 pm
Location: ~/

Re: [solved]Reading command inputted

Fri May 07, 2021 5:10 pm

Well the function of the code is above the quoted reply

What would you set it as, considering it will be running user commands for terminal
Running with a Raspberry Pi 4B 4GB with Raspberry Pi OS with MATE Desktop
Why not overclock, push some more performance out of your computer!
Think before you delete something a stranger on the internet told you to.

dsyleixa123
Posts: 1435
Joined: Mon Jun 11, 2018 11:22 am

Re: [solved]Reading command inputted

Fri May 07, 2021 5:14 pm

RaspbianUser1 wrote:
Fri May 07, 2021 3:42 pm
I ended up setting the variable as

Code: Select all

char command[4096];
Would you recommend higher?
if you can hold out accidental (more or less quite unlikely) crashes, take an appropriate value (1000, 4000, 65000, whatever).
My advice: if you want to make more flexible and more failsafe, use std::string (as already had been stated above).

Heater
Posts: 18202
Joined: Tue Jul 17, 2012 3:02 pm

Re: [solved]Reading command inputted

Fri May 07, 2021 5:18 pm

RaspbianUser1 wrote:
Fri May 07, 2021 5:10 pm
Well the function of the code is above the quoted reply

What would you set it as, considering it will be running user commands for terminal
Impossible to say.

What does "running user commands for terminal" mean? That may well include simple things like:

Code: Select all

$ ./mu_prog `ls`
Where that `ls` could produce a very long list of very long arguments.
Memory in C++ is a leaky abstraction .

Return to “C/C++”