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: Awhile 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