Hogyan lehet hurkolni egy fájl sorain?

Mondja, hogy nekem van ez a fájl:

hello world hello world 

Ez a program

#!/bin/bash for i in $(cat $1); do echo "tester: $i" done 

kimenetek

tester: hello tester: world tester: hello tester: world 

Szeretném, ha a for az egyes sorok iterálása, külön-külön figyelmen kívül hagyva a szóközöket, vagyis az utolsó két sort le kell cserélni a következőre:

tester: hello world 

Idézetek használata for i in "$(cat $1)"; azt eredményezi, hogy i az egész fájlt egyszerre kapja meg. Mit kell változtatnom?

Válasz

(9 évvel később 🙂
Mindkét feltett válasz nem fog sikerülni a fájlokon új sor nélkül, ez gyakorlatilag kihagyja az utolsó sort, nem okoz hibát, katasztrófához vezet (keményen megtanulták) módon :).

A legjobb tömör megoldás, amelyet eddig találtam, hogy “Just Works” (mind bashban, mind sh-ben):

while IFS="" read -r LINE || [ -n "${LINE}" ]; do echo "processing line: ${LINE}" done < /path/to/input/file.txt 

Részletesebb beszélgetésért lásd ezt a StackOverflow beszélgetést: Hogyan kell használni a ” olvassa el a “(Bash) elemet a fájl utolsó sorának elolvasásához, ha nincs új sor a fájl végén?

Vigyázat: ez a megközelítés további új sort ad az utolsó sorhoz, ha van már egyik sem.

Hozzászólások

  • Szép fogás, köszönöm! Ne feledje, hogy " Vigyázzon, hogy ez további új sort ad hozzá az EOF-nél, ha még nincs ilyen. / div> megjegyzés bár
  • Tóbiás, én ' hozzáadom ezt jegyzetként, köszönöm.

Válasz

for és IFS használatával / a>:

#!/bin/bash IFS=$"\n" # make newlines the only separator set -f # disable globbing for i in $(cat < "$1"); do echo "tester: $i" done 

Ne feledje azonban, hogy az üres sorokat kihagyja, mivel newline IFS-szóköz karakter, szekvenciák ebből 1-nek számít, és a vezető és a mögötteseket figyelmen kívül hagyják. A zsh és ksh93 (nem bash) lehetőségekkel megváltoztathatja IFS=$"\n\n" hogy az új sort ne külön kezeljük, azonban vegye figyelembe, hogy az összes záró új sor karaktert (így az üres sorokat is) mindig eltávolítja a parancscsere.

Vagy a következővel: read (nincs több cat ):

#!/bin/bash while IFS= read -r line; do echo "tester: $line" done < "$1" 

Ott üres sorok megmaradnak, de vegye figyelembe, hogy kihagyná az utolsó sort, ha új vonalas karakter nem határozná meg megfelelően.

Megjegyzések

  • köszönöm, nem tudtam ' nem tudtam, hogy < egy egész ciklusba. Bár teljesen logikus, most láttam
  • Úgy látom, hogy IFS \ read -r line' in second example. Is really IFS = `szükséges? IMHO elég annyit mondani, hogy: while read -r line; do echo "tester: $line"; done < "$1"
  • @GrzegorzWierzowiecki IFS= kikapcsolja a vezető és a záró szóköz eltávolítását. Lásd: A while IFS= read.. cikkben miért nincs hatása az IFS-nek?
  • @BenMares A hamisítás megakadályozása érdekében az olvasott szövegben esetleg megjelenő kifejezések kibővítésétől az egyező fájlnevekig. Próbáljon meg például printf '%s\n' '*o' 'bar' >afile; touch foo; IFS=$'\n'; for i in $(cat afile); do echo "$i"; done.
  • A while IFS= read -r line || [ "$line" ]; do egy olyan záró sort fog feldolgozni, amelyet új vonalas karakter nem határol be helyesen. (de vissza lesz adva).

Válasz

Annak érdekében, hogy mit ér, meg kell tennem hogy elég gyakran, és soha nem emlékszem az while IFS= read... használatának pontos módjára, ezért a következő függvényt definiáltam a bash profilomban:

# iterate the line of a file and call input function iterlines() { (( $# < 2 )) && { echo "Usage: iterlines <File> <Callback>"; return; } local File=$1 local Func=$2 n=$(cat "$File" | wc -l) for (( i=1; i<=n; i++ )); do "$Func" "$(sed "${i}q;d" "$File")" done } 

Ez a függvény először meghatározza a fájl sorainak számát, majd a sed segítségével kivonja a sort a sor után, és minden sort egyetlen karakterlánc argumentumként továbbít bármely adott funkció. Feltételezem, hogy ez nagymértékben hatástalanná válhat nagy fájlok esetén, de ez eddig nem jelentett problémát számomra (természetesen javaslatok ennek az üdvözlésnek a javítására).

A felhasználás nagyon édes IMO: / p>

>> cat example.txt # note the use of spaces, whitespace, etc. a/path This is a sentence. "wi\th quotes" $End >> iterlines example.txt echo # preserves quotes, $ and whitespace a/path This is a sentence. "wi\th quotes" $End >> x() { echo "$#"; }; iterlines example.txt x # line always passed as single input string 1 1 1 1 1 

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük