C programming: how to ignore an input? - c

I'm new to C language so please don't be harsh on me. I want to run a program this way : ./test -option 3,2 < text.txt
I want to execute the program regardless of the file exists or not.
So that ./test -option 3,4,2 < text.txt is the same as ./test -option 3,4,2
without
getting the message *-bash: hehe: No such file or directory*
Thanks

You can use a ternary:
[ -f test.txt ] && ./test -option 3,2 < test.txt || echo "" | ./test -option 3,2
In order to avoid repeating the command, you can also use:
CMD="./test -option 3,2"; [ -f test.txt ] && $CMD < test.txt || echo "" | $CMD
Also, notice that test is a command, consider using another name for your program.

Related

how to "hang" file with the uso of cycle for

I started now with the bash script and I'm trying to make a for loop that uses an array where there are the arguments passed to the script (2 or more files) trying to "hang" with the ">>" command, the first ones "n-1" files passed as argument to the last file (n) , writing the input files in the order from right to left
for example :
myscript.sh file1 file2 file3 file4
file4 will contain in sequence file3 file2 file1
arr=($#)
j=$#-1
for i in { j-1..0..1 }
do
cat arr[i] >> $[j]
done
I tried to do it this way but it doesn't work, can someone help me?
Try:
#!/bin/bash
n=$#
for i in $(seq $((n - 1)) -1 1) ; do
cat ${#:$i:1} >> ${#:$n:1}
done
Explanation:
seq $((n - 1)) -1 1 generates the numbers from $n - 1 to 1 in reverse order.
${#:$i:1} gives the element $i of the array of the arguments of the script.
Or, without seq:
#!/bin/bash
n=$#
for ((i = n - 1; i; i--)) ; do
echo "cat ${#:$i:1} >> ${#:$n:1}"
done
Or even shorter, with a while loop instead of a for loop, and maybe off topic for this reason:
#!/bin/bash
i=${#}
while ((--i)) ; do
echo "cat ${#:$i:1} >> ${#:$#:1}"
done
Not sure what about "hang", but this concatenates the first files to the last filename
cat "${#:0:$#}" > "${#: -1:1}"
this is slicing the the arguments.
You could print all arguments except the last one on separate lines, reverse the files order and then cat all of them into the file that is the last argument:
printf "%s\n" "${#:1:$#-1}" | tac | xargs cat > "${#: -1}"
The same using zero as the stream separator:
printf "%s\0" "${#:1:$#-1}" | tac -s '' | xargs -0 cat > "${#: -1}"
It would be very advisable to protect against the count of arguments less then 2, because when $# = 0 then ${#: -1} will be $0. Then $0 could be your shell with ex full path like /bin/bash, so > could overwrite your shell executable file!
So do:
if (($# >= 2)); then printf "%s\0" "${#:1:$#-1}" | tac -s '' | xargs -0 cat > "${#: -1}"; fi

Storing Command Line Arguments in an Array , Arguments can be Integers OR a file containing integers delimited by a space

Requirement :
Able to send a file containing numbers (433 434 435) as a parameter
sh Test.sh myFile.txt
Parameters can be numbers directly if not a file (433 434 434)
sh Test.sh 434 435 436
So , it has to support both file and numbers as the parameters
Below is the code i ve tried writing but in the for loop below , all numbers are getting printed as a string , but i need the for loop to run thrice as the input values are 3.
How to have it as a part of an array in shell script
Iam relatively new to shell script
OutPut:
In either case for loop has to run the number of parameter times(filedata determinies the parameters or direct input)
Please advice if any unforeseen bugs exist
#!/bin/bash
echo -e $# 2>&1 ;
myFile=$1 ; // As the first parameter will be a file
#[ -f "$myFile" ] && echo "$myFile Found" || echo "$myFile Not found"
if [ -f "$myFile" ]; then
tcId=`cat $#`;
echo $tcId;
else
tcId=$#;
echo $tcId;
fi
# Execute each of the given tests
for testCase in "$tcId"
do
echo "Test Case is "$testCase ;
done
I'd use a process substitution to "pretend" the explicit arguments are in a file.
while IFS= read -r testCase; do
echo "Test case is $testCase"
done < <( if [ -f "$1" ]; then
cat "$1"
else
printf "%s\n" "$#"
fi
)
If you are flexible in how your script is called, I would simplify it to only read test cases from standard input
while IFS= read -r testCase; do
echo "Test case is $testCase"
done
and call it one of two ways, neither using command line arguments:
sh Test.sh < myFile.txt
or
sh Test.sh <<TESTCASES
433
434
434
TESTCASES

How to output 'passed' if a diff command results in no difference in bash?

I am writing a shell script that loops over my ./tests directory and uses the unix diff command to compare .in and .out files against each other for my C program. Here is my shell script:
#! /usr/bin/env bash
count=0
# Loop through test files
for t in tests/*.in; do
echo '================================================================'
echo ' Test' $count
echo '================================================================'
echo 'Testing' $t '...'
# Output results to (test).res
(./snapshot < $t) > "${t%.*}.res"
# Test with diff against the (test).out files
diff "${t%.*}.res" "${t%.*}.out"
echo '================================================================'
echo ' Memcheck
echo '================================================================'
# Output results to (test).res
(valgrind ./snapshot < $t) > "${t%.*}.res"
count=$((count+1))
done
My question is how can I add an if statement to the script that will output 'passed' if the diff command results in no difference? e.g.
pseudo code:
if ((diff res_file out_file) == '') {
echo 'Passed'
} else {
printf "Failed\n\n"
diff res_file out_file
}
Get and check the exit code from the diff command. diff has an exit code of 0 if no differences were found.
diff ...
ret=$?
if [[ $ret -eq 0 ]]; then
echo "passed."
else
echo "failed."
fi
The answer by #jstills worked for me however I modified it slightly and thought I'd post my result as an answer too to help others
Once I understood that diff has an exit code of 0 I modified my code to this. It checks if diff exits with 0 or >1 for each difference if I understand correctly. My code then sends the output of diff to /dev/null so it won't be displayed to stdout and I then do my check and print passed or failed to the stdout and if failed the differences with sdiff which display differences side by side.
if diff "${t%.*}.res" "${t%.*}.out" >/dev/null; then
printf "Passed\n"
else
printf "Failed\n"
sdiff "${t%.*}.res" "${t%.*}.out"
fi

Problems Writing Output to File

I am reading in a small csv file in the format size,name - one set per line. For my testing file I have two lines in the csv file.
If I use the code
while
IFS=',' read -r size name
do
printf "%s\n" "name"
done < temp1.txt
The name values for each of the lines is printed to the terminal.
If I use the code
while
IFS=',' read -r size name
do
printf "%s\n" "name" > temp2.txt
done < temp1.txt
Then only the last name is printed to the temp2.txt file.
What am I doing wrong?!
You are using >, so that the file gets truncated every time. Instead, use >> to append:
So it should be like this:
printf "%s\n" "name" >> temp2.txt
^^
All together:
while
IFS=',' read -r size name
do
printf "%s\n" "name" >> temp2.txt
done < temp1.txt
Basic example:
$ echo "hello" > a
$ echo "bye" > a
$ cat a
bye # just last line gets written
$ echo "hello" >> a
$ echo "bye" >> a
$ cat a
hello
bye # everything gets written

pipe awk output into c program

Hi I have written a c program that takes 3 integers as input:
./myprogram 1 2 3
and I am aiming to pipe data from a csv file into the input of the c program. I grab each line from the c program using:
for i in $(seq 1 `wc -l "test.csv" | awk '{print $1}'`); do sed -n $i'p' "test.csv"; done;
and then would like to pipe the output of this into my c program. I have tried doing:
for i in $(seq 1 `wc -l "test.csv" | awk '{print $1}'`); do sed -n $i'p' "test.csv"; done; | ./myprogram
however I get:
Line
bash: syntax error near unexpected token `|'
how do I pipe the output into my c program?
Thanks
It helps when you really try to understand error messages the shell gives you:
Line
bash: syntax error near unexpected token `|'
If you think about it, when you chain commands together in a pipeline, there is never a ; before a |, for example:
ls | wc -l
# and not: ls; | wc -l
Whatever comes after a ; is like an independent new command, as if you typed it on a completely new, clear command line. If you type | hello on a clear command line, you'll get the exact same error, because that's the exact same situation as ; | ... in your script, for example:
$ | hello
-bash: syntax error near unexpected token `|'
Others already answered this, but I also wanted to urge you to make other improvements in your script:
Always use $() instead of backticks, for example:
for i in $(seq 1 $(wc -l "test.csv" | awk '{print $1}')); ...
You didn't need the awk there, this would work just as well:
for i in $(seq 1 $(wc -l "test.csv")); ...
You could reduce your entire script to simply this, for the same effect:
./myprogram < test.csv
In the shell, it doesn't like an explicit line termination followed by a pipe (|). The pipe already delimits the commands. So you want:
for i in $(seq 1 `wc -l "test.csv" | awk '{print $1}'`); do sed -n $i'p' "test.csv"; done | ./myprogram

Resources