it-swarm-eu.dev

Jak číst ze dvou vstupních souborů pomocí while while

Chtěl jsem vědět, jestli existuje nějaký způsob, jak číst ze dvou vstupních souborů ve vnořené chvíli smyčky po jednom řádku. Například řekněme, že mám dva soubory FileA a FileB.

FileA:

[jaypal:~/Temp] cat filea
this is File A line1
this is File A line2
this is File A line3

FileB:

[jaypal:~/Temp] cat fileb
this is File B line1
this is File B line2
this is File B line3

Aktuální ukázkový skript:

[jaypal:~/Temp] cat read.sh 
#!/bin/bash
while read lineA
    do echo $lineA 
    while read lineB
        do echo $lineB 
        done < fileb
done < filea

Provedení:

[jaypal:~/Temp] ./read.sh 
this is File A line1
this is File B line1
this is File B line2
this is File B line3
this is File A line2
this is File B line1
this is File B line2
this is File B line3
this is File A line3
this is File B line1
this is File B line2
this is File B line3

Problém a požadovaný výstup:

To smyčky přes FileB úplně pro každý řádek v FileA. Snažil jsem se používat pokračovat, přerušit, ukončit, ale žádný z nich není určen k dosažení výstupu, který hledám. Chtěl bych, aby skript četl pouze jeden řádek ze souboru A a poté jeden řádek ze souboru FileB a ukončil smyčku a pokračoval druhým řádkem souboru A a druhým řádkem souboru B. Něco podobného následujícímu skriptu -

[jaypal:~/Temp] cat read1.sh 
#!/bin/bash
count=1
while read lineA
    do echo $lineA 
        lineB=`sed -n "$count"p fileb`
        echo $lineB
        count=`expr $count + 1`
done < filea

[jaypal:~/Temp] ./read1.sh 
this is File A line1
this is File B line1
this is File A line2
this is File B line2
this is File A line3
this is File B line3

Lze toho dosáhnout pomocí smyčky while?

27
jaypal singh

Pokud víte, že určitá postava se nikdy neobjeví v prvním souboru, můžete použít vložit.

Příklad vložení pomocí výchozí karty oddělovače:

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

Příklad vložení pomocí @:

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

Pamatujte, že stačí, pokud je zaručeno, že se znak v prvním souboru neobjeví. Je to proto, že read bude při vyplňování poslední proměnné ignorovat IFS. Takže i když @ Nastane ve druhém souboru, nebude rozdělen.

Příklad vložení pomocí některých funkcí bash pro pravděpodobně čistší kód:

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

Použité funkce Bash: ansi c string ($'\t') A substituce proces (<(...)) na vyhněte se smyčce while) v subshell problém .

Pokud si nemůžete být jisti, že se v obou souborech nikdy neobjeví žádný znak, můžete použít popisovače souborů .

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

Netestováno moc. Mohlo by dojít k přerušení prázdných řádků.

Deskriptory souborů číslo 0, 1 a 2 se již používají pro stdin, stdout a stderr. Deskriptory souborů od 3 a výše jsou (obvykle) zdarma. Manuál pro basy varuje před použitím deskriptorů souborů větších než 9, protože se používají „interně“.

Všimněte si, že popisovače otevřeného souboru jsou zděděny pro funkce prostředí Shell a externí programy. Funkce a programy zděděné otevřeným deskriptorem souboru mohou číst (a zapisovat) z deskriptoru souboru. Před zavoláním funkce nebo externího programu byste měli zavřít všechny popisovače souborů, které nejsou nutné.

Zde je stejný program jako výše s tím, že skutečná práce (tisk) byla oddělena od meta-práce (paralelní čtení řádků po dvou souborech).

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

Nyní předstíráme, že nemáme žádnou kontrolu nad pracovním kódem a že kód se z jakéhokoli důvodu snaží číst z popisovače souborů 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

Zde je příklad výstupu. Všimněte si, že druhý řádek z prvního souboru je „odcizen“ ze smyčky.

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

Zde je popis, jak byste měli zavřít popisovače souborů před voláním externího kódu (nebo jakéhokoli kódu v této věci).

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
33
lesmana

Otevřete dva soubory na různých popisovače souborů . Přesměrujte vstup zabudovaného read do deskriptoru, ke kterému je připojen požadovaný soubor. Do bash/ksh/zsh můžete napsat read -u 3 namísto read <&3.

while IFS= read -r lineA && IFS= read -r lineB <&3; do
  echo "$lineA"; echo "$lineB"
done <fileA 3<fileB

Tento úryvek se zastaví po zpracování nejkratšího souboru. Viz Čtení dvou souborů do IFS while loop - Existuje v tomto případě způsob, jak získat nulový rozdíl? , pokud chcete pokračovat ve zpracování až do konce obou souborů.

Viz také Kdy byste použili další deskriptor souboru? pro další informace o deskriptorech souborů, a Proč se používá `while IFS = read` tak často, místo` IFS =; během čtení ..`? pro vysvětlení IFS= read -r.

Vím, že chcete skript Shell, ale možná byste se měli podívat na příkaz paste.

4
lutzky

Vyzkoušejte níže uvedený příkaz:

paste -d '\n' inp1.txt inp2.txt > outfile.txt
3
Shree

Případně předpokládám, že byste mohli pomocí příkazu bash's mapfile vložit soubor do proměnné pole, která spojuje každý řádek souboru do pole [line_of_file_index]. Nejsem si však jistý, zda je pouze pro Bash3 vyšší nebo Bash4.

http://wiki.bash-hackers.org/commands/builtin/mapfile

0
Nikhil Mulley