0

Assume that I have a file like this:

[inp] // This is the file name
2
1 2 3
5 7 9

This would be read in C++ using this code:

main()
{
    freopen("inp","r",stdin); // Redirect stdin to file, while open the file in read mode
    int n; cin >> n; // A variable to get the numbers of lines. n = 2 in this case and the file cursor is after the first line
    for (int i = 0; i < n; i++) // n-time loop
    {
        int a, b, c; // 3 numbers to save 3 values on each line
        cin >> a >> b >> c; // Read the numbers from each line. The file cursor after each loop is at the end of a line
        doSomething(a, b, c); // Do something with 3 read variables.
    }
}

Which means in C++, we can control the file cursor. My code in bash:

inp="./inp" # file name
n=$(head -1 $inp) # Get numbers of line to read
for i in {1..$n}
do
    echo * | head -1 $inp | awk '{print $1;}' < $inp
done

Instead of getting only 1 and 5 from each line, the output I get was 2 1 5 on 3 lines. So I would think that we can't control the file cursor in bash. Are there any solution to this?

1 Answers1

0

Yes, you can control the cursor in bash when reading a file, but in order to do that, you need to use a single file redirect operation (<), which would be equivalent to an open() or similar in C/C++.

Here is code in bash that is mostly equivalent to the C++ code you mentioned:

do_something () {
  local linenumber
  linenumber=$1
  shift
  echo "doing something with args $* from line $linenumber"
}

inp="./inp" # file name

{ read numlines
  for ((i = 1; i <= numlines; i++)); do
    read a b c
    do_something "$i" "$a" "$b" "$c"
  done
} <"$inp"

As you can see, there's a single <"$inp" redirect. And all the commands reading from the file (inside the { ... } block, in this case) are sharing that file descriptor, including the cursor position where the file was left after the previous operation.

filbranden
  • 21,751
  • 4
  • 63
  • 86
  • 2
    In a shell script (as in C++ in this example), it would look nicer if one read until there was nothing more to read. The first piece of info in the file (number of lines to read) is rather useless. while read -r a b c; do do_something "$a" "$b" "$c"; done <input – Kusalananda Jun 17 '19 at 06:18
  • what does shift in do_something() do then? – minhperry Jun 17 '19 at 12:11
  • @infrustration The shift in do_something() skips the first argument ($i with the line number), so that $* only includes the three other arguments ($a, $b and $c). – filbranden Jun 17 '19 at 12:26