Skip to main content
deleted 135 characters in body
Source Link
Lesmana
  • 28.1k
  • 20
  • 85
  • 87

If you know for surecan guarantee that some character will never occur in the first file then you can use paste.

Example of paste using default delimiter tab:

paste file1 file2 | while IFS="$(printf '\t')" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

Example of paste usingFor example you know for sure that @ will never occur:

Example of paste using some bash features for arguably cleaner code and paste using default delimiter tab:

If you cannot be certain that any character will never occur in both files then you can use two file descriptors.

If you know for sure that some character will never occur in the first file then you can use paste.

Example of paste using default delimiter tab:

paste file1 file2 | while IFS="$(printf '\t')" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

Example of paste using @:

Example of paste using some bash features for arguably cleaner code:

If you cannot be certain that any character will never occur in both files then you can use file descriptors.

If you can guarantee that some character will never occur in the first file then you can use paste.

For example you know for sure that @ will never occur:

Example using some bash features for arguably cleaner code and paste using default delimiter tab:

If you cannot be certain that any character will never occur in both files then you can use two file descriptors.

added 947 characters in body
Source Link
Lesmana
  • 28.1k
  • 20
  • 85
  • 87

If you know for sure that some character will never occur in both filesthe first file then you can use paste.

Note that open file descriptors are inherited to shell functions and external programs. Functions and programs inheriting an open file descriptor can be read by anyone so youfrom (and write to) the file descriptor. You should take care to close them as soonall file descriptors which are not required before calling a function or external program.

Here is the same program as you don't need them anymoreabove with the actual work (the printing) separated from the meta-work (reading line by line from two files in parallel).

progwork() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
}

while true
do
  #read here-r wef1 try<&3 || break
  read from-r fd3f2 <&4 || break
  work "$f1" "$f2"
done 3<file1 4<file2

Now we pretend that we have no control over the work code and that code, for whatever reason, tries to read from file descriptor 3.

unknowncode() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
  read -r yoink <&3 && printf 'yoink: %s\n' "$yoink"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  unknowncode "$f1" "$f2"
done 3<file1 4<file2

Here is an example output. Note that the second line from the first file is "stolen" from the loop.

f1: file1 line1
f2: file2 line1
yoink: file1 line2
f1: file1 line3
f2: file2 line2

Here is how you should close the file descriptors before calling external code (or any code for that matter).

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  # this will close fd3 and fd4 before executing proganycode
  proganycode "$f1" "$f2" 3<&- 4<&-
  # note that fd3 and fd4 are still open in the loop
done 3<file1 4<file2

This is an example output if run without closing the file descriptors (without this part: 3<&- 4<&-):

f1: file1 line1
f2: file2 line1
yoink: file1 line2
f1: file1 line3
f2: file2 line2

If you know for sure that some character will never occur in both files then you can use paste.

Note that open file descriptors can be read by anyone so you should close them as soon as you don't need them anymore.

prog() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
  # here we try read from fd3
  read -r yoink <&3 && printf 'yoink: %s\n' "$yoink"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  # this will close fd3 and fd4 before executing prog
  prog "$f1" "$f2" 3<&- 4<&-
  # note that fd3 and fd4 are still open in the loop
done 3<file1 4<file2

This is an example output if run without closing the file descriptors (without this part: 3<&- 4<&-):

f1: file1 line1
f2: file2 line1
yoink: file1 line2
f1: file1 line3
f2: file2 line2

If you know for sure that some character will never occur in the first file then you can use paste.

Note that open file descriptors are inherited to shell functions and external programs. Functions and programs inheriting an open file descriptor can read from (and write to) the file descriptor. You should take care to close all file descriptors which are not required before calling a function or external program.

Here is the same program as above with the actual work (the printing) separated from the meta-work (reading line by line from two files in parallel).

work() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  work "$f1" "$f2"
done 3<file1 4<file2

Now we pretend that we have no control over the work code and that code, for whatever reason, tries to read from file descriptor 3.

unknowncode() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
  read -r yoink <&3 && printf 'yoink: %s\n' "$yoink"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  unknowncode "$f1" "$f2"
done 3<file1 4<file2

Here is an example output. Note that the second line from the first file is "stolen" from the loop.

f1: file1 line1
f2: file2 line1
yoink: file1 line2
f1: file1 line3
f2: file2 line2

Here is how you should close the file descriptors before calling external code (or any code for that matter).

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  # this will close fd3 and fd4 before executing anycode
  anycode "$f1" "$f2" 3<&- 4<&-
  # note that fd3 and fd4 are still open in the loop
done 3<file1 4<file2
added 524 characters in body
Source Link
Lesmana
  • 28.1k
  • 20
  • 85
  • 87

If you know for sure that some character will never occur in both files then you can use paste.

Example of paste using default delimiter tab:

paste file1 file2 | while IFS="$(printf '\t')" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

Example of paste using @:

paste -d@ file1 file2 | while IFS="@" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

Note that it is enough if the character is guaranteed to not occur in the first file. This is because read will ignore IFS when filling the last variable. So even if @ occurs in the second file it will not be split.

Example of paste using some bash features for arguably cleaner code:

while IFS=$'\t' read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done < <(paste file1 file2)

Bash features used: ansi c string ($'\t') and process substitution (<(...)) to avoid the while loop in a subshell problem.

If you cannot be certain that any character will never occur in both files then you can use file descriptors.

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done 3<file1 4<file2

Not tested much. Might break on empty lines.

File descriptors number 0, 1, and 2 are already used for stdin, stdout, and stderr, respectively. File descriptors from 3 and up are (usually) free. The bash manual warns from using file descriptors greater than 9, because they are "used internally".

Note that open file descriptors can be read by anyone so you should close them as soon as you don't need them anymore.

prog() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
  # here we try read from fd3
  read -r yoink <&3 && printf 'yoink: %s\n' "$yoink"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  # this will close fd3 and fd4 before executing prog
  prog "$f1" "$f2" 3<&- 4<&-
  # note that fd3 and fd4 are still open in the loop
done 3<file1 4<file2

This is an example output if run without closing the file descriptors (without this part: 3<&- 4<&-):

f1: file1 line1
f2: file2 line1
yoink: file1 line2
f1: file1 line3
f2: file2 line2

If you know for sure that some character will never occur in both files then you can use paste.

Example of paste using default delimiter tab:

paste file1 file2 | while IFS="$(printf '\t')" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

Example of paste using @:

paste -d@ file1 file2 | while IFS="@" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

Example of paste using some bash features for arguably cleaner code:

while IFS=$'\t' read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done < <(paste file1 file2)

If you cannot be certain that any character will never occur in both files then you can use file descriptors.

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done 3<file1 4<file2

Not tested much. Might break on empty lines.

File descriptors number 0, 1, and 2 are already used for stdin, stdout, and stderr, respectively. File descriptors from 3 and up are (usually) free. The bash manual warns from using file descriptors greater than 9, because they are "used internally".

Note that open file descriptors can be read by anyone so you should close them as soon as you don't need them anymore.

prog() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
  # here we try read from fd3
  read -r yoink <&3 && printf 'yoink: %s\n' "$yoink"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  # this will close fd3 and fd4 before executing prog
  prog "$f1" "$f2" 3<&- 4<&-
  # note that fd3 and fd4 are still open in the loop
done 3<file1 4<file2

This is an example output if run without closing the file descriptors (without this part: 3<&- 4<&-):

f1: file1 line1
f2: file2 line1
yoink: file1 line2
f1: file1 line3
f2: file2 line2

If you know for sure that some character will never occur in both files then you can use paste.

Example of paste using default delimiter tab:

paste file1 file2 | while IFS="$(printf '\t')" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

Example of paste using @:

paste -d@ file1 file2 | while IFS="@" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

Note that it is enough if the character is guaranteed to not occur in the first file. This is because read will ignore IFS when filling the last variable. So even if @ occurs in the second file it will not be split.

Example of paste using some bash features for arguably cleaner code:

while IFS=$'\t' read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done < <(paste file1 file2)

Bash features used: ansi c string ($'\t') and process substitution (<(...)) to avoid the while loop in a subshell problem.

If you cannot be certain that any character will never occur in both files then you can use file descriptors.

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done 3<file1 4<file2

Not tested much. Might break on empty lines.

File descriptors number 0, 1, and 2 are already used for stdin, stdout, and stderr, respectively. File descriptors from 3 and up are (usually) free. The bash manual warns from using file descriptors greater than 9, because they are "used internally".

Note that open file descriptors can be read by anyone so you should close them as soon as you don't need them anymore.

prog() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
  # here we try read from fd3
  read -r yoink <&3 && printf 'yoink: %s\n' "$yoink"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  # this will close fd3 and fd4 before executing prog
  prog "$f1" "$f2" 3<&- 4<&-
  # note that fd3 and fd4 are still open in the loop
done 3<file1 4<file2

This is an example output if run without closing the file descriptors (without this part: 3<&- 4<&-):

f1: file1 line1
f2: file2 line1
yoink: file1 line2
f1: file1 line3
f2: file2 line2
added 608 characters in body
Source Link
Lesmana
  • 28.1k
  • 20
  • 85
  • 87
Loading
added 608 characters in body
Source Link
Lesmana
  • 28.1k
  • 20
  • 85
  • 87
Loading
added 308 characters in body
Source Link
Lesmana
  • 28.1k
  • 20
  • 85
  • 87
Loading
Source Link
Lesmana
  • 28.1k
  • 20
  • 85
  • 87
Loading