[Ubuntu 14.04, GNU Awk 4.0.1]
I have a strange problem... I am assigning a numeric value, that is retrieved from an input file, to a custom variable. When I print it, it displays correctly, and printing its length displays the right number of digits.
However, when I use the variable in a loop, my loop stops when index becomes greater than the most significant digit of my variable.
I have tried a For Loop, and now a While Loop, both suffer the same problem.
With the file I'm processing, samples contains the value 8092, and the loop stops on the 9th iteration.
#!/usr/bin/awk -f
BEGIN {
samples = 0;
}
{
...
samples = $24;
}
END {
i = 1;
while (i <= samples ) {
if (i>samples) { print "This is the end.\n " i " is bigger than " samples;}
i++;
}
}
I am very new to AWK, and can't see why this is occurring. After reading a number of tutorials, I'm under the impression that AWK is able to convert between string & numeric representations of numbers as required.
Can someone help me see what I've done wrong?
Solution
The answer was, as JNevill & ghoti suggested, to add 0 to the variable. In my case, the best place was just before the loop, as samples` is rewritten during the body of the AWK script. Thanks.
Awk doesn't exactly "convert" between representations, it simply uses whatever you give it, adjusting context based on usage. Thus, when evaluating booleans, any non-zero number evaluates to TRUE, and any string except "0" evaluates to TRUE.
I can't see what's really in your samples variable, but if you want to force things to be evaluated as a number before you start your loop, you might be able to simple add zero to the variable I.e.:
samples = $24 + 0;
Also, if your source data came from a DOS/Windows machine and has line endings that include carriage returns (\r\n), and $24 is the last field on each line, then you may be comparing i against 24\r, which is likely not to give you the results you expect.
To see what's really in your input data, try:
cat -vet samples | less
If you see ^M before the $ at the end of each line, then your input file contains carriage returns, and you should process it appropriately before asking awk to parse its content.
In fact, I think it's pretty clear that since your input data begins with the character "8" and your loop stops on the 9th iteration, your comparison of i to samples is one of strings rather than numbers.
awk decides the type of variable depending on what value is held in the variable. You can force it to type the way you want, though it's a bit hackey (isn't everything though).
Try adding 0 to your variable before hitting the for loop. $sample = $sample + 0, for instance. Now no matter what awk thought before you hit that line, it will now treat your number as a number and your for loop should execute as expected.
Odd though that it was executing at all and stopping at 9 iterations.... It suggests that perhaps it is already treating it correctly and you may be assuming that the value is 8092, when it is, in fact 9. Also, that printed bit inside your for loop should never execute. Hopefully it doesn't output that.
Related
I've started work on a Variable banner program, and I've hit a "phantom" syntax error.
name = input('Type here: ')
namelist = list(namelist)
print(namelist)
length_of_name=len(namelist)
asterisk=('*')
for length_of_name:
print (asterisk)
it throws up a syntax error, as I mentioned, but can anyone spot what I did wrong?
The SyntaxError is coming from your for statement. A for statement has to look like for variable in sequence_object:. Here sequence_object is any type that can be iterated, such as a list or tuple, but in your particular case for i in range(0,length_of_name): will make the code syntactically correct. But don't use this because there is a faster way which makes exactly the same output.
Instead of printing a single character in a loop, set asterisk to '*\n' and use print(asterisk*length_of_name, end=''). This prints the same output as the for loop but this multiplies the asterisk character by an integer to make a string that is repeated that many times. That way, you only print once. Setting end to an empty string ensures that a blank line is not printed.
I have a string, such as time=1234, and I want to extract just the number after the = sign. However, this number could be in the range of 0 and 100000 (eg. - time=1, time=23, time=99999, etc.).
I've tried things like $(string:5:8}, but this will only work for examples of a certain length.
How do I get the substring of everything after the = sign? I would prefer to do it without outside commands like cut or awk, because I will be running this script on devices that may or may not have that functionality. I know there are examples out there using outside functions, but I am trying to find a solution without the use of such.
s=time=1234
time_int=${s##*=}
echo "The content after the = in $s is $time_int"
This is a parameter expansion matching everything matching *= from the front of the variable -- thus, everything up to and including the last =.
If intending this to be non-greedy (that is, to remove only content up to the first = rather than the last =), use ${s#*=} -- a single # rather than two.
References:
The bash-hackers page on parameter expansion
BashFAQ #100 ("How do I do string manipulations in bash?")
BashFAQ #73 ("How can I use parameter expansion? How can I get substrings? [...])
BashSheet quick-reference, paramater expansion section
if time= part is constant you can remove prefix by using ${str#time=}
Let's say you have str='time=123123' if you execute echo ${str#time=} you would get 123123
First and foremost, I'm not familiar with Perl at all. I've been studying C++ primarily for the last 1/2 year. I'm in a class now that that is teaching Linux commands, and we have short little topics on languages used in Linux, including Perl, which is totally throwing me for a loop (no pun intended). I have a text file that contains a bunch of random numbers separated by spaces and tabs, maybe even newlines, that gets read into the program via a filehandle. I'm supposed to write 2 lines of code that split the lines of numbers and merge them into one array, inside of a foreach loop. I'm not looking for an answer, just a nudge in the right direction. I've been trying different things for multiple hours and feel totally silly I can't get it, I'm totally lost with the syntax. Its just a bit odd not working inside a compiler and out of my comfort zone working outside of C++. I really appreciate it. I've included a few photos. Basically, the code we are writing it just to store the numbers and the rest of the program will determine the smallest number and sum of all numbers. Mine is currently incorrect because I'm not sure what to do. In the output photo, it will display all the numbers being entered in via the text file, so you can see them.
Several things to fix here. First of all, please don't post screenshots of your sample data or code, as it makes it impossible to copy and paste to test your code or data. Post your code/data by indenting it with four spaces and a newline preceding the code block.
Add use strict; in your script. This should be lesson 0 in your class. After that add my to all variable declarations.
To populate #all_numbers with contents of each line's numbers, without using push, you can use something like this:
foreach my $line (#output_lines)
{
my #numbers = split /\s/, $line;
#all_numbers = (#all_numbers, #numbers);
}
You say you're "not looking for an answer," so here's your nudge:
You're almost there. You split each line well (using split/\s/) and store the numeric values in #all_numbers. However, notice that each time around in the loop, you replace (using the assignment, #all_numbers = ...) the whole contents of #all_numbers with the numbers you found in the current line. Effectively, you're throwing away everything you've stored from the previous lines.
Instead, you want to add to #all_numbers, not replace #all_numbers. Have a look at the push() function for how to do this.
NB: Your split() call is fine, but it's more customary to use split(' ', $line) in this case. (See split(): you can use a single space, ' ', instead of the pattern, /\s/, when you want to split on any whitespace.)
I hope you need to store the all splitting element into array, so you looking for push function.
foreach $line (#input_lines)
{
push(#all_numbers,split(/\s/,$line));
}
Your problem is, in every iteration, the splitted value is over written in an array not to append together. For example,
#array = qw(one two three);
#array = qw(five four seven);
print "#array";
output is five four seven not the one two three five four seven because this is reinitialize with a new values. You want to append the new values in the array in before or after use unshift or push
for example
#array = qw(one two three);
push(#array,qw(five four seven));
Another way:
my #all_numbers = map { split ' ', $_ } #output_lines;
See http://perldoc.perl.org/functions/map.html
I have to write a MATLAB function with the following description:
function counts = letterStatistics(filename, allowedChar, N)
This function is supposed to open a text file specified by filename and read its entire contents. The contents will be parsed such that any character that isn’t in allowedChar is removed. Finally it will return a count of all N-symbol combinations in the parsed text. This function should be stored in a file name “letterStatistics.m” and I made a list of some commands and things of how the function should be organized according to my professors' lecture notes:
Begin the function by setting the default value of N to 1 in case:
a. The user specifies a 0 or negative value of N.
b. The user doesn’t pass the argument N into the function, i.e., counts = letterStatistics(filename, allowedChar)
Using the fopen function, open the file filename for reading in text mode.
Using the function fscanf, read in all the contents of the opened file into a string variable.
I know there exists a MATLAB function to turn all letters in a string to lower case. Since my analysis will disregard case, I have to use this function on the string of text.
Parse this string variable as follows (use logical indexing or regular expressions – do not use for loops):
a. We want to remove all newline characters without this occurring:
e.g.
In my younger and more vulnerable years my father gave me some advice that I've been turning over in my mind ever since.
In my younger and more vulnerableyears my father gave me some advicethat I’ve been turning over in my mindever since.
Replace all newline characters (special character \n) with a single space: ' '.
b. We will treat hyphenated words as two separate words, hence do the same for hyphens '-'.
c. Remove any character that is not in allowedChar. Hint: use regexprep with an empty string '' as an argument for replace.
d. Any sequence of two or more blank spaces should be replaced by a single blank space.
Use the provided permsRep function, to create a matrix of all possible N-symbol combinations of the symbols in allowedChar.
Using the strfind function, count all the N-symbol combinations in the parsed text into an array counts. Do not loop through each character in your parsed text as you would in a C program.
Close the opened file using fclose.
HERE IS MY QUESTION: so as you can see i have made this list of what the function is, what it should do, and using which commands (fclose etc.). the trouble is that I'm aware that closing the file involves use of 'fclose' but other than that I'm not sure how to execute #8. Same goes for the whole function creation. I have a vague idea of how to create a function using what commands but I'm unable to produce the actual code.. how should I begin? Any guidance/hints would seriously be appreciated because I'm having programmers' block and am unable to start!
I think that you are new to matlab, so the documentation may be complicated. The root of the problem is the basic understanding of file I/O (input/output) I guess. So the thing is that when you open the file using fopen, matlab returns a pointer to that file, which is generally called a file ID. When you call fclose you want matlab to understand that you want to close that file. So what you have to do is to use fclose with the correct file ID.
fid = open('test.txt');
fprintf(fid,'This is a test.\n');
fclose(fid);
fid = 0; % Optional, this will make it clear that the file is not open,
% but it is not necessary since matlab will send a not open message anyway
Regarding the function creation the syntax is something like this:
function out = myFcn(x,y)
z = x*y;
fprintf('z=%.0f\n',z); % Print value of z in the command window
out = z>0;
This is a function that checks if two numbers are positive and returns true they are. If not it returns false. This may not be the best way to do this test, but it works as example I guess.
Please comment if this is not what you want to know.
I took the following example literally from Walter Savitch Absolute C++ book. It works (as one would expect from a scholar such as Walter Savitch). However, I am puzzled why as I will explain after the code citation:
cout << "Enter a line of input and I will echo it:\n";
char symbol;
do
{
cin.get(symbol);
cout << symbol;
} while (symbol != '\n');
cout << "That's all for this demonstration.\n";
Possible output will look as follows:
Enter a line of input and I will echo it:
Do Be Do 1 2 34
Do Be Do 1 2 34
That's all for this demonstration.
My problem is the following. In going through the loop just once, cin.get(symbol) will find one character at a time, and cout will then output this one character consequently. Then, if my input wasn't a '\n' character, it will go into the loop for the second time, and so on, until finally the input equals '\n'.
However, in executing the code, all the input seems to be read at once, and then copied back at once. How can this happen if every input character needs to be checked to be equal to '\n'?
Final point, probably stating the obvious: this question does not pertain to code that is some way not syntactical. I am just puzzled about what happens during compilation and/or execution of the simple code I present above.
Hopefully someone can help me out!
Thanks.
Your observation is correct. It seems like all the input is read at once and then, printed out at once. The reason is that when the output is printed, it goes into a buffer which actually gets printed only when the buffer reaches a certain size, or whenever the code is all done. In the latter case, the output stream is closed and gets flushed. Practically speaking, this code is being printed but into a buffer.
Well it looks like it's gettings handled at once, because it is. The loop is going on exactly as you've written - keeps on writing the char until it meets the end of line mark. There isn't really much logic behind it :)