I'm quite new to Linux and not familiar with C. Here I have one question about both.
I'm writing a C program to run in Linux. And I have a file names f.txt in the same folder. With some fields like this:
Jason 12 Male
I want to compare the $2 of the txt file of each line with the value of parameter a. If the second field of the line is greater than a, then print the first field $1.
I tried codes like this but not work. Can anybody help? Thanks!
void main()
{ int a;
scanf("%d",&a);
char* comm="awk '{if($2>"+a+") print $1}' f.txt";
system(comm);
}
For your stated problem, which is just basic text file processing, it is probably easiest to solve this task using a scripting language itself, rather than using C (such as python, perl, or awk itself).
For your programming problem, the C language does not support that kind of string concatenation. You have to build the string using a call to snprintf() (or via calls to strcat()).
char comm[512];
int r = snprintf(comm, sizeof(comm), "awk '{if($2>%d) print $1}' f.txt", a);
if (r < 0) {
/* error */
} else if (r < sizeof(comm)) {
/* ok */
} else {
/* need a bigger comm buffer... */
}
An alternative approach to handling this problem would be the following: Read the bytes from stdin with the following snippet:
while ( ( char *data = scanf( "%s %d %s\n" ) ) != EOF )
... where the newline is your delimiter. Then you can perform the appropriate actions on "data" to access each field individually.
It would be ran by piping your text file to the program:
./program < textfile.txt
Related
I'm using the cat command for a school project.
What i need is to give a txt file as input to my code and then evaluate the output (saved in a txt file).
So far i'm using this in my command line:
cat input_000.txt | ./main > my_output.txt
Where ./main is my C code.
The input_000.txt is structured like this:
0 a a R 3
1 a b L 4
4 c b R 1
ecc...
I have a certain number of lines made of 5 characters (with spaces between them).
How do i get the content of each line in my C code? I've been told so use standard input, but i've always used scanfonly from keyboard input.
Does it still work in this case?
And how should i save my output? I usually use fwrite, but in this case is everything managed by the cat command
That's how pipes works, it sets up so the output of the left-hand side of the pipe will be written to standard input for the right-hand side program.
In short if you can read input from stdin (like you do with plain scanf) then you won't have to do any changes at all.
Redirection works just about the same. Redirecting to a file (>) will make all writes to stdout go to the file. Redirecting from a file (<) will make all reads from stdin come from the file.
You can use getline (or scanf indeed) to read the stdin (fd = 0) and save it in a char* in your C code... Then you only need to write in the stdout (fd = 1) and your > will do the job to write in your file
What you need is something like this inside your function...
FILE *input = fopen("input.txt","rw"); //rw (read-write)
FILE *output= fopen("output.txt","rw"); //rw (read-write)
char inputArray[500];
char outputArray[500];
while(fscanf(input,"%s", inputArray) != EOF){
//read the line and save in 'inputArray'
//you can also use %c to find each caracter, in your case I think it's better...you can //save each caracter in a array position, or something like that
}
while(number of lines you need or the number of lines from your input file){
fprintf(output,"%s\n",output); //this will write the string saved in 'outputArray'
}
If you don't want to use it...then you can give your main.c the input using < and saving the output >
./main.o < input.txt > output.txt
(something like that, its not safer because the terminal could have the settings to use other type of charset...
I have a binary file which prints the result instead of returning the value, if I execute it using cmd I am getting printed text, I managed to execute it from C code but it seems like I can not get the text it usually prints to be stored in a variable I can use later for further decisions.
I do not have that much of experience in C and I googled a lot.
I came across the idea of using clip but my cmd is saying that clip command can not be found.
any help or ideas would be appreciated.
The correct function pair to use on POSIX systems is popen() and
pclose(). You can perhaps use Microsoft's _popen() and
_pclose() unless the warning 'This API cannot be used in applications that execute in the Windows Runtime' matters to you.
You would use it more or less like this. I've had to invent the name of the command you wish to execute since the question doesn't specify that. I chose ./example.exe as the name — and I'm assuming it needs no arguments.
char cmd[] = "./example.exe";
FILE *fp = popen(cmd, "r");
if (fp != NULL)
{
char buffer[4096];
size_t nbytes;
while ((nbytes = fread(buffer, sizeof(buffer), sizeof(char), fp)) != 0)
{
…process nbytes of data…
…it is not a null-terminated string unless you add the null byte…
}
pclose(fp);
}
else
{
…report error for failure to execute command…
}
You can use the system function from <stdlib.h> to run the command you want. To get the command's output, you modify your command like in this question to save the command's output to a file. Then you can use the file I/O functions in <stdio.h> to process the command output.
In Linux, you may do command substitution and pass its result as arguments to the program, Something like this
./your_program "$(/path/to/your/binary/file)"
Suppose your main is
int main(int argc,char* argv[]){
.
.
return 0;
}
Acess the arguments like argv[1] and so.
Here the $(command) does the substitution and it passes the printed values from the binary as arguments to the pgm. Hope this helps.
Use snprintf function. For e.g.
snprintf(cmdbuff, BUFFER_LEN, "dmidecode --type 17 | grep -i Size | grep -o '\\<[0-9]*\\>' | paste -sd+ | bc");
Here cmdbuff is character array where command will be stored , BUFFER_LEN is a size of the character array
Then use popen and fgets to get the output of command into some buffer as shown below
if((fd = popen(cmdbuff,"r")) != NULL)
{
fgets(buffer, BUFFER_LEN, fd);
sprintf(vnfc_configured_memory, "%s", buffer);
vnfc_configured_totalRAM = atof(vnfc_configured_memory);
}
I want to compute the checksum of a txt file using C in mac, thus I wrote a simple program as
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
FILE *in;
char buff[512];
if(!(in = popen("shasum ritesh_file_test.txt", "r")))
{
return 1;
}
while(fgets(buff, sizeof(buff), in)!=NULL)
{
cout << buff;
}
printf ("checksum = %s",buff);
pclose(in);
return 0;
it prints the checksum of txt file , but also it prints the path of file. as
30b574b4ddbc681d9e5e6492ae82b32a7923e02e ritesh_file_test.txt
How do I get rid of this path and only access the checksum value?
The output format of shasum is of form
<HASH> <Filename>
so, the hash value and the file name are separated by a space. One possible way, to separate the hash from the complete outpuy, is to tokenize buff before printing.
You can make use of strtok() and use space () as delimiter to take out only the checksum value.
That said, in C, you don't include #include <iostream>, don't use using namespace std; and don't write cout. Moreover, use a C compiler to compile C code.
Three solutions:
Since you are using a shell, shasum ritesh_file_test.txt | awk '{ print $1; }' might work.
Since you are using C++:
std::string checksum(buff);
checksum = checksum.substr(0, checksum.find(' ') -1 );
Or even, since a hash is always 40 bytes:
std::string checksum(buff, 40);
I leave error checking as an exercise for you!
I'm trying to write a program that accept file names as arguments in a bash script, then passes them to a C program that replaces spaces with underscores, then the bash script uses that to rename the file.
For example, the input would be
Bash bash_script "test test test.txt"
and the file would be renamed test_test_test.txt.
My problem is that when I run this, it tells me that I'm using mv incorrectly. Why is this? I'm new to bash, so I'm sorry for using program/script incorrectly.
My C program:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i = 0;
char * file = argv[1];
while(i<=256){ //max file size is 256 characters on mac
if (argc != 2)
printf("Please provide one file name.");
else if(file[i] == ' ')
file[i] = '_';
i++;
}
printf("%s \n", file);
return 0;
}
My Bash program:
#! /bin/bash
VAR = "C_program '$#'"
mv $1 $VAR
This line:
VAR = "C_program '$#'"
doesn't do what you want. And your mv line is broken too.
VAR=$(C_program "$#")
mv "$1" "$VAR"
Also, your C program doesn't exit with an error when an error is detected.
Also, sed and tr are existing programs that are suitable alternatives to writing your C program to transliterate (translate) characters in strings.
Also, rename/prename are existing (Perl) programs that handle rename files with regular expression pattern functionality to rename files, which may be already available on your system(s).
In your specific example, I would not shell out to a custom C program to do this.
Here's an equivalent shell script (not requiring tr, sed or any programs besides bash and mv):
mv "$1" "${1// /_}"
In your specific problem, you are not setting your VAR properly. Shell scripts cannot accept spaces around the = when setting variables, and you need to use backticks or $() to execute an external program. So, properly written, you want
VAR="$(C_program "$#")"
If you just want the results than I would suggest simply replace the bash script and custom C program with a single short Bourne or POSIX shell script.
#!/bin/sh
NEW_FILE_NAME= `echo $1 | tr ' ' _ `
mv $1 $NEW_FILE_NAME
Otherwise
You want the shell script to run your C program (I'll refer to it as todash for simplicity) before setting the shell variable VAR. This is done using the backtick ` (located near upper right corner of US keyboards with tilde, '~') operation.
#!/bin/sh
VAR= `todash $1`
mv $1 $VAR
For todash.c I'll suggest a couple of mostly small improvements.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(int argc, char *argv[])
{
char * filename;
/* Program operates on filename, not file or its contents, so use a variable
name that reflect that. Good variable names make debugging easier.
*/
if (argc != 2) {
printf("Please provide one file name.");
return EXIT_FAILURE; /* or exit(EXIT_FAILURE); */
} else {
/* Only set filename, once known that argv[1] is not NULL (empty) */
filename = argv[1];
}
/* Use a simple for loop
* PATH_MAX is a standard system constant included with limits.h
*/
for (i = 0; (i < PATH_MAX) && (filename[i] != '\0'); i++) {
if (filename[i] == ' ') {
filename[i] = '_';
}
}
printf("%s \n", filename);
return EXIT_SUCCESS;
}
The added length is only my additional inline comments.
The largest change was untangling the argc if comparison from the while loop, which once simplified, become a classic example of where to use a for loop.
And for your sanity, and those around you, use braces (curly brackets) around conditional blocks of code. Just because you are allowed to not include them, does not mean you should (not include them). Programs tend to live beyond their original intention and expand in the future. Avoid making mistakes later by including them now.
2 problems with the mv $1 "C_program '$#'"
$1 needs double quotes -> "$1"
"C_program '$#'" should be `C_program '$1'` or $(C_program '$#')
however this can be done more efficiently with
IFS="
"
for x in $#; do
mv "$x" "${x// /_}"
done
Let me start by saying this is associated with a homework assignment. However, this is a very small and relatively insignificant part of the assignment.
The C program receives input via command line arguments but it needs to be in the form:
$ ./program < input
How, would I go about receiving that input as a string? Each time I try to print out the 3rd argument from argv I receive this message:
input: No such file or directory.
< is a shell redirect - it is handled outside your program. What you'll see is the contents of the file name 'input' being send to your standard input stream. This is a common way for programs to operate, although they usually also handle being given a file name e.g. sed.
If I had to guess I would think the:
input: No such file or directory.
is coming from the shell, as it is unable to open the file specified: "input".
On the other hand, if you actually want the < input as arguments to your program, you can escape or quote them so the shell won't interpret them. (Escaping left as an exercise for the reader :-)).
The ./program < input syntax is a special shell syntax saying "Redirects everything in the file named input to the standard entry of the program".
To read the input, your program just have to use standard input reading functions, line fgets or scanf.
On *nix systems, there won't be a third element of argv. If you execute that command on almost any Unix-like shell, it will be similar to doing this:
cat input | ./program
So your ./program has only one element in argv, but it's stdin is the file input, so to read the file you would just read from stdin. Note that this is a perfectly valid way to design your program. Many Unix programs read from standard input if no files are given, so that you may pipe in input from other programs (or in this case, from files).
What comes after the < is not a command-line argument. The contents of the file will be piped into your program by the shell.
All you need to do is read from stdin and you'll get the contents of the file.
You need to escape the '<', otherwise shell will parse it, and program won't receive it in command-line.
If you're using bash, then:
./program '<' input
or
./program \< input
Other shells might do it differently (e.g. Windows' default, cmd.exe, uses ^ as escape character, not \).
This is a Unix shell thing. The form someprogram < somefile tells someprogram to run using somefile as its input. If you want to do something different involving the < symbol, you'll need to quote it.
The < means that the program will read it's standard input (stdin) from the named file (input). So just read from stdin (using fgets, fread, etc).
Leave off the '<'. You want command line arguments do this:
$ ./program -Dflag seven=ixnay FromDinger
In your application, try this:
int main( int argc, char **argv )
{
int i;
for( i = 0 ; i < argc ; ++i )
printf( "Arg %d = %s\n", i, argv[i] );
return 0;
}
You'll notice that the first argument is the name of the executable (at index 0), and your second argument (at index 1) will be "-Dflag"
Actually, this is a very common technique used in programming tournaments. The data your program needs is stored in a file, let's say data.txt , and then redirected to your application using the "<" on the shell, like this: ./program < data.txt
So, in your source code, what you need to do is something like this:
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
string tmp;
string full_content;
while (cin >> tmp)
full_content += " "+tmp;
cout << full_content << endl;
}
.. and you'll get all the data from the file on a string (and separated by spaces).
That's one way to do it, I hope it helps.
[]'s
You can get it by reading stdin.