How to Do a While Loop with a String Redirected into It

How to do a while loop with a string redirected into it

You had the right idea with your 2nd snipit but you need to use 'Here Strings' via the <<< syntax. You cant access $TEST_STRING outside of your first snipit because the pipe creates a sub-shell; using the here-string does not. Also, make sure you quote "$HTTP_LINKS" otherwise you'll lose the newlines.

#!/bin/bash

HTTP_LINKS=$(echo -e "http://www.aaa.com\nhttp://www.bbb.com")

unset TEST_STRING;

while read url;
do
((TEST_STRING++))
done <<<"$HTTP_LINKS"

echo $TEST_STRING

Output

2

C - Reading a string & int from stdin (or redirect from file)

You need to allocate memory for str, try char str[256] instead of char * str.

Also remove the scanf from the bottom of the while loop, it's not necessary.

using input redirection in while loop

The idiomatic way to read a sequence of white-space separated integers in C++ would be

#include <iostream>
using namespace std;

int main () {
int input;
while (cin >> input) {
cout << input + 1 << endl;
}
return 0;
}

Let's come to why this works the way it does.

cin >> input

discards possible white-space and then reads an integer from the standard input. Moreover, it returns a reference of the cin object used. With this returned reference, you can call the bool conversion operator to check if any of the fail bits is set in the given std::basic_ios object. So

while (cin >> input)

does two things. Read an integer from standard input and check if it successfully completed the operation. As long as this operation succeeds, your while loop continues to iterate and you print the numbers.

See http://en.cppreference.com/w/cpp/io/basic_istream/operator_gtgt for reference on std::basic_istream::operator>>.

See http://en.cppreference.com/w/cpp/io/basic_ios/operator_bool for reference on operator bool.

Edit1: Move references to bottom so that the answer is more readable.

Variable loss in redirected bash while loop

First of all, simplify your script! Usually there are many better ways in bash. Also most of the time you can rely on pure bash solutions instead of running awk or other tools.

Then add some debbuging!
Here is a bit refactored script with debugging

#!/bin/bash
for ip in "$(ifconfig | grep -oP 'inet addr:\K[0-9.]+')"
do
bytesin=0
bytesout=0
while read -r line
do
read -r subIp _ _ increment _ <<< "$line"
if [[ $subIp == "$ip" ]]
then
((bytesout+=increment))
else
((bytesin+=increment))
fi
# some debugging
echo "line: $line"
echo "subIp: $subIp"
echo "bytesin: $bytesin"
echo "bytesout: $bytesout"
done <<< "$(pmacct -s | grep "$ip")"
echo "$ip $bytesin $bytesout" >> /tmp/bwacct.txt
done

Much clearer now, huh? :)

File redirection for loops in the shell

There's only one stdin that you redirect in the loop. Both read and awk will read from that stdin. While the read only consumes one line (the first), awk happily consumes the rest.

In the next iteration, read has nothing more to read and the loop terminates.

If you want to provide data on awk's stdin, you must do so explicitly, e.g. by piping into awk with printf '%s\n' "$line" | awk ....

How to redirect grep to a while loop

The problem is in this line:

done << (grep -w "token" "$file")
# ^^

You need to say < and then <(). The first one is to indicate the input for the while loop and the second one for the process substitution:

done < <(grep -w "token" "$file")
# ^ ^

Note however that there are many others things you want to check. See the comments for a discussion and paste the code in ShellCheck for more details. Also, by indicating some sample input and desired output I am sure we can find a better way to do this.

Redirecting output of bash for loop

Remove your semicolon.

for i in `seq 2`; do echo "$i"; done > out.dat

SUGGESTIONS

Also as suggested by Fredrik Pihl, try not to use external binaries when they are not needed, or at least when practically not:

for i in {1..2}; do echo "$i"; done > out.dat
for (( i = 1; i <= 2; ++i )); do echo "$i"; done > out.dat
for i in 1 2; do echo "$i"; done > out.dat

Also, be careful of outputs in words that may cause pathname expansion.

for a in $(echo '*'); do echo "$a"; done

Would show your files instead of just a literal *.

$() is also recommended as a clearer syntax for command substitution in Bash and POSIX shells than backticks (`), and it supports nesting.

The cleaner solutions as well for reading output to variables are

while read var; do
...
done < <(do something)

And

read ... < <(do something)  ## Could be done on a loop or with readarray.

for a in "${array[@]}"; do
:
done

Using printf can also be an easier alternative with respect to the intended function:

printf '%s\n' {1..2} > out.dat

Improve bash script to echo redirect within loop

When the redirection is inside the loop the output file is opened and closed every single iteration. If you redirect the entire loop it's opened for the duration of the loop, which is much, much faster.

for ((i = 0; i < 1000000; ++i)); do
echo "test statement redirected into file a million times"
done > /tmp/output.txt

(Note also the updated loop logic.)

If you want to make it even faster, you can speed it up by simplifying this to one or two commands that loop internally rather than looping in the shell script. yes will output a fixed string over and over. Combine it with head to control how many lines are printed.

yes 'test statement redirected into file a million times' | head -1000000 > /tmp/output.txt

Will mounting the tmp directory in RAM make it faster?

Maybe, but I wouldn't bother. That's a system-wide change for a local problem. If you don't need the file on disk, it raises the question: do you even need to create the file in the first place? Why do you need a file with the same line repeated a million times? Maybe this is an XY problem. Perhaps you don't need the file at all.

For instance, if you're creating it and immediately passing it to a single subsequent command, you could try using process substitution instead to avoid needing a temp file.

yes 'test statement redirected into file a million times' | head -1000000 > /tmp/output.txt
command /tmp/output.txt

becomes

command <(yes 'test statement redirected into file a million times' | head -1000000)


Related Topics



Leave a reply



Submit