Paspauskite failo turinį Bash

Kaip galiu pasikartoti per kiekvieną teksto failo eilutę, naudojant „ bash“ ?

Naudojant šį scenarijų:

 echo "Start!" for p in (peptides.txt) do echo "${p}" done 

Gaunu šį išėjimą ekrane:

 Start! ./runPep.sh: line 3: syntax error near unexpected token '(' ./runPep.sh: line 3: 'for p in (peptides.txt)' 

(Vėliau noriu padaryti kažką sudėtingesnio, kai $p tik rodymas ekrane.)


Aplinkos kintamasis SHELL (nuo env):

 SHELL=/bin/bash 

Išvestis /bin/bash --version :

 GNU bash, version 3.1.17(1)-release (x86_64-suse-linux-gnu) Copyright (C) 2005 Free Software Foundation, Inc. 

išvesties cat/proc/version :

 Linux version 2.6.18.2-34-default (geeko@buildhost) (gcc version 4.1.2 20061115 (prerelease) (SUSE Linux)) #1 SMP Mon Nov 27 11:46:27 UTC 2006 

Faile peptides.txt yra:

 RKEKNVQ IPKKLLQK QYFHQLEKMNVK IPKKLLQK GDLSTALEVAIDCYEK QYFHQLEKMNVKIPENIYR RKEKNVQ VLAKHGKLQDAIN ILGFMK LEDVALQILL 
1049
05 окт. Nustatė Peter Mortensen spalio 5 d 2009-10-05 20:52 '09 20:52 val. 2009-10-05 20:52
@ 11 atsakymų

Vienas iš būdų tai padaryti yra:

 while read p; do echo "$p" done <peptides.txt 

Kaip nurodyta komentaruose, tai turi šalutinį poveikį: nukirpti pirmaujančias erdves, interpretuoti grįžtamojo sluoksnio sekas ir praleisti nugarą, jei nėra galinės linijos. Jei tai yra problema, galite:

 while IFS="" read -rp || [ -n "$p" ] do printf '%s\n' "$p" done < peptides.txt 

Išskirtiniais atvejais, jei kilpos korpusas gali skaityti iš standartinės įvesties , galite atidaryti failą naudodami kitą failų deskriptorių:

 while read -u 10 p; do ... done 10<peptides.txt 

Čia 10 yra tik savavališkas skaičius (išskyrus 0, 1, 2).

1662
05 окт. Bruno De Fraine atsakymas 05 okt. 2009-10-05 21:00 '09 21:00 val. 2009-10-05 21:00
 cat peptides.txt | while read line do # do something with $line here done 
324
05 окт. Warren Young spalio 5 d. Atsakymas 2009-10-05 20:54 '09 20:54 val. 2009-10-05 20:54

1a variantas: ciklo ciklas: viena eilutė: įvesties peradresavimas

 #!/bin/bash filename='peptides.txt' echo Start while read p; do echo $p done < $filename 

1b variantas: kilpa: viena eilutė:
Atidarykite failą, skaitykite iš failo deskriptoriaus (šiuo atveju failo deskriptorius # 4).

 #!/bin/bash filename='peptides.txt' exec 4<$filename echo Start while read -u4 p ; do echo $p done 

2 variantas . Ciklui: failo skaitymas viename kintamajame ir analizėje.
Ši sintaksė išanalizuos „eilutes“ pagal bet kurią tarpą tarp žetonų. Tai vis dar veikia, nes nurodytos įvesties failo eilutės yra vieno žodžio žetonai. Jei eilutė turėjo daugiau nei vieną simbolį, šis metodas neveiks. Be to, viso failo skaitymas viename kintamajame nėra gera strategija dideliems failams.

 #!/bin/bash filename='peptides.txt' filelines='cat $filename' echo Start for line in $filelines ; do echo $line done 
122
05 окт. atsakymas pateikiamas Stan Graves 05 spalis. 2009-10-05 21:18 '09 21:18 val. 2009-10-05 21:18

Tai nėra geriau nei kiti atsakymai, tačiau tai dar vienas būdas gauti darbą faile be tarpų (žr. Komentarus). Manau, kad dažnai reikia vieno įdėklo, kad pereitumėte tekstinių failų sąrašus be papildomo žingsnio naudojant atskirus scenarijų failus.

 for word in $(cat peptides.txt); do echo $word; done 

Šis formatas leidžia man visa tai įdėti į vieną komandų eilutę. Pakeiskite „echo $ word“ dalį, kurią norite, ir galite išleisti kelias komandas, atskirtas kabliataškiais. Toliau pateiktame pavyzdyje failo turinys naudojamas kaip argumentai dviejuose skriptuose, kuriuos galbūt parašėte.

 for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done 

Arba, jei ketinate jį naudoti kaip srauto redaktorių (išmokti „sed“), išvestį galite perduoti kitam tokiam failui.

 for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done > outfile.txt 

Naudojau juos kaip parašyta aukščiau, nes naudoju tekstinius failus, kur juos sukūriau vienu žodžiu kiekvienoje eilutėje. (Žr. Komentarus) Jei turite tarpų, kurių nenorite atskirti savo žodžių / eilučių, jis tampa šiek tiek bjaurus, bet ta pati komanda vis dar veikia taip:

 OLDIFS=$IFS; IFS=$'\n'; for line in $(cat peptides.txt); do cmd_a.sh $line; cmd_b.py $line; done > outfile.txt; IFS=$OLDIFS 

Tai tiesiog pasakoja, kad lukštais padalijamos tik naujos eilutės, o ne tarpai, o tada grįžta į aplinką atgal į tai, kas buvo anksčiau. Šiuo metu galbūt norėsite visa tai įdėti į scenarijų apvalkalą, o ne suspausti ją į vieną eilutę.

Sėkmės!

67
04 окт. atsakymas pateikiamas 04 04. 2013-10-04 16:30 '13, 16.30 val. 2013-10-04 16:30

Naudokite laiką, pvz .:

 while IFS= read -r line; do echo "$line" done <file 

Pastabos:

42
09 июня '15 в 18:09 2015-06-09 18:09 „ Jahid“ atsakymą pateikė birželio 09-15 dienomis 18:09 2015-06-09 18:09

Dar keletas dalykų, kuriems netaikomi kiti atsakymai:

Skaitymas iš atskirtų failų

 # ':' is the delimiter here, and there are three fields on each line in the file # IFS set below is restricted to the context of 'read', it doesn't affect any other code while IFS=: read -r field1 field2 field3; do # process the fields # if the line has less than three fields, the missing fields will be set to an empty string # if the line has more than three fields, 'field3' will get all the values, including the third field plus the delimiter(s) done < input.txt 

Skaitymas iš kitos komandos išvesties naudojant proceso pakeitimą

 while read -r line; do # process the line done < <(command ...) 

Šis požiūris yra geresnis už command... | while read -r line; do... command... | while read -r line; do... command... | while read -r line; do... command... | while read -r line; do... command... | while read -r line; do... command... | while read -r line; do... command... | while read -r line; do... command... | while read -r line; do... command... | while read -r line; do... nes tuo metu kilpa veikia dabartiniame apvalkale, o ne subshell, kaip ir pastarojo atveju. Žr. Susiję įrašai . Kintamasis pakeistas viduje, kai kilpa neprisimenama .

Skaitymas iš nulinio padalinio įvesties, pvz., find... -print0

 while read -r -d '' line; do # logic # use a second 'read ... <<< "$line"' if we need to tokenize the line done < <(find /path/to/dir -print0) 

Susiję skaitymai: BashFAQ / 020 - Kaip rasti ir saugiai tvarkyti failų pavadinimus, kuriuose yra eilutės pertraukos, tarpai ar abu?

Skaitymas iš daugiau nei vieno failo vienu metu

 while read -u 3 -r line1  read -u 4 -r line2; do # process the lines # note that the loop will end when we reach EOF on either of the files, because of the ' done 3< input1.txt 4< input2.txt 

Remiantis @chepner atsakymu čia :

-u yra bash pratęsimas. Suderinamumui su POSIX, kiekvienas skambutis atrodys panašus: read -r X <> .

Viso failo skaitymas į masyvą (versija Bash anksčiau nei 4)

 while read -r line; do my_array+=("$line") done < my_file 

Jei failas baigiasi nebaigta linija (pabaigoje nėra naujos eilutės), tada:

 while read -r line || [[ $line ]]; do my_array+=("$line") done < my_file 

Viso failo skaitymas į masyvą (versija Bash 4x ir naujesnė)

 readarray -t my_array < my_file 

arba

 mapfile -t my_array < my_file 

Ir tada

 for line in "${my_array[@]}"; do # process the lines done 

Susiję įrašai:

42
14 янв. Atsakymą pateikia kodas 21 2017-01-14 06:30 '17 at 6:30 2017-01-14 06:30

Jei nenorite, kad skaitymas būtų suskaidytas nauja eilute, naudokite -

 #!/bin/bash while IFS='' read -r line || [[ -n "$line" ]]; do echo "$line" done < "$1" 

Tada paleiskite scenarijų failo pavadinimu kaip parametrą.

13
08 марта '16 в 19:10 2016-03-08 19:10 atsakymą pateikė Anjul Sharma kovo 16 d. 16:10 2016-03-08 19:10

Tarkime, kad turite šį failą:

 $ cat /tmp/test.txt Line 1 Line 2 has leading space Line 3 followed by blank line Line 5 (follows a blank line) and has trailing space Line 6 has no ending CR 

Yra keturi elementai, kurie pakeis daugelio „Bash“ sprendimų nuskaityto failo išvesties vertę:

  1. Tuščia linija 4;
  2. Važiuojantys arba galiniai tarpai dviejose eilutėse;
  3. Atskirų linijų vertės išsaugojimas (t.y. kiekviena eilutė yra įrašas);
  4. 6 eilutė nesibaigia CR.

Jei norite, kad teksto failo eilutėje būtų tuščios eilutės ir linijos be CR, turite naudoti truputį kilpą ir turite turėti alternatyvų testą paskutinei eilutei.

Čia pateikiami metodai, galintys modifikuoti failą (palyginti su cat grąžinimu):

1) Pralaimėkite paskutinę eilutę, o taip pat ir pirmaujančias bei galines vietas:

 $ while read -rp; do printf "%s\n" "'$p'"; done </tmp/test.txt 'Line 1' 'Line 2 has leading space' 'Line 3 followed by blank line' '' 'Line 5 (follows a blank line) and has trailing space' 

(Jei darote, while IFS= read -rp; do printf "%s\n" "'$p'"; done </tmp/test.txt , taupote tarpus, while IFS= read -rp; do printf "%s\n" "'$p'"; done </tmp/test.txt ir pabaigoje, bet vis tiek prarasite paskutinę eilutę, jei ji nesibaigia CR)

2) Naudojant pakaitinį procesą su cat bus perskaitytas visas failas vienoje pakopoje ir prarandama atskirų linijų vertė:

 $ for p in "$(cat /tmp/test.txt)"; do printf "%s\n" "'$p'"; done 'Line 1 Line 2 has leading space Line 3 followed by blank line Line 5 (follows a blank line) and has trailing space Line 6 has no ending CR' 

(Jei pašalinsite iš „ $(cat/tmp/test.txt) jūs perskaitysite failą žodžiais, o ne viename kate. Taip pat tikriausiai ne tai, kas skirta ...)


Patikimiausias ir paprastiausias būdas skaityti failo eilutę pagal eilutę ir išsaugoti visas vietas:

 $ while IFS= read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt 'Line 1' ' Line 2 has leading space' 'Line 3 followed by blank line' '' 'Line 5 (follows a blank line) and has trailing space ' 'Line 6 has no ending CR' 

Jei norite pašalinti pagrindines ir prekybos vietas, pašalinkite IFS= dalį:

 $ while read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt 'Line 1' 'Line 2 has leading space' 'Line 3 followed by blank line' '' 'Line 5 (follows a blank line) and has trailing space' 'Line 6 has no ending CR' 

(Tekstinis failas be nugaros, nors gana dažnai yra laikomas skaldytu pagal POSIX. Jei galite pasikliauti vergais, jums nereikia || [[ -n $line ]] per while .)

Daugiau apie BASH DUK

11
03 февр. atsakymas pateikiamas 03 vasario mėn. 2016-02-03 22:15 '16 at 10:15 pm 2016-02-03 22:15
 #!/bin/bash # # Change the file name from "test" to desired input file # (The comments in bash are prefixed with #'s) for x in $(cat test.txt) do echo $x done 
4
14 нояб. atsakymą pateikė Sine lapkričio 14 d. 2013-11-14 17:23 '13, 17:23, 2013-11-14 17:23

Štai mano realaus gyvenimo pavyzdys, pavyzdžiui, kitos programos išvesties linijos, tikrinant antraštes, nustatant dvigubas kabutes iš kintamojo, naudojant šį kintamąjį už kilpos ribų. Manau, kad daugelis šių klausimų anksčiau ar vėliau užduoda šiuos klausimus.

 ##Parse FPS from first video stream, drop quotes from fps variable ## streams.stream.0.codec_type="video" ## streams.stream.0.r_frame_rate="24000/1001" ## streams.stream.0.avg_frame_rate="24000/1001" FPS=unknown while read -r line; do if [[ $FPS == "unknown" ]]  [[ $line == *".codec_type=\"video\""* ]]; then echo ParseFPS $line FPS=parse fi if [[ $FPS == "parse" ]]  [[ $line == *".r_frame_rate="* ]]; then echo ParseFPS $line FPS=${line##*=} FPS="${FPS%\"}" FPS="${FPS#\"}" fi done <<< "$(ffprobe -v quiet -print_format flat -show_format -show_streams -i "$input")" if [ "$FPS" == "unknown" ] || [ "$FPS" == "parse" ]; then echo ParseFPS Unknown frame rate fi echo Found $FPS 

Norėdami deklaruoti kintamąjį už kilpos ribų, nustatyti vertę ir naudoti ją už kilpos ribų, turite atlikti sintaksę „<<< $ (...)“. Programa turi būti paleista dabartinės konsolės kontekste. Citatos aplink komandą išsaugo naujas išvesties srauto eilutes.

Tada suderinamoji kilpa, skirta antraštėms, nuskaito vardo = vertės porą, padalina dešinę paskutiniojo simbolio pusę, išmeta pirmąją citatą, sukasi paskutinę citatą, turime grynąją vertę, kuri bus naudojama kitur.

3
30 июня '15 в 11:15 2015-06-30 11:15 atsakymą pateikė „ Whome“ birželio 30 d., 15 val. 11:15 2015-06-30 11:15

@Peter: jis gali dirbti jums -

 echo "Start!";for p in $(cat ./pep); do echo $p done 

Tai grąžins rezultatą -

 Start! RKEKNVQ IPKKLLQK QYFHQLEKMNVK IPKKLLQK GDLSTALEVAIDCYEK QYFHQLEKMNVKIPENIYR RKEKNVQ VLAKHGKLQDAIN ILGFMK LEDVALQILL 
1
30 авг. atsakymas, kurį pateikė Alan Jebakumar 30 rug . 2015-08-30 08:00 '15 8:00 2015-08-30 08:00

Kiti klausimai apie „ žymes arba Ask a Question