2012-06-11 12 views
17

W Javie, jeśli wiesz, że plik jest bardzo mały, możesz użyć metody readBytes(), aby przeczytać treść za jednym zamachem, zamiast czytać wiersz po linii lub używając bufora.Jak odczytywać zawartość pliku do zmiennej za jednym razem?

prostu zastanawiasz się w skrypcie, wiem, że możemy zrobić coś takiego:

while read line 
    do 
     echo $line 
     LINE = $line 
    done < "test.file" 
    echo $LINE 

Jeśli moja test.file jest jak:

testline1 
testline2 
testline3 

to tylko daje mi ostatnią linię do $LINE. $LINE zawiera "testline3".

Moje pytanie brzmi: jak mogę odczytać cały plik z wieloma liniami w jedną zmienną, aby uzyskać $LINE="testline1\ntestline2\ntestline3"?

+1

'data = $ (cat plik)', ale dlaczego miałbyś chcieć? Po prostu przeczytaj ten plik, gdy tylko potrzebujesz treści! –

+1

Dwie rzeczy niezwiązane bezpośrednio z twoim pytaniem: po pierwsze, 'LINE = $ line' nie działa; przestrzeń wokół znaku równości powoduje, że jest on nieważny. Po drugie, jeśli manipulujesz tekstem, który chcesz zachować dosłownie, powinieneś ustawić 'IFS' na wartość null dla twoich wywołań odczytu (w przeciwnym wypadku wiodące białe znaki na każdej linii będą nukowane) i przekazują opcję' -r' do 'odczytania' i opcja '-E' do' echo' (w przeciwnym razie wszelkie ukośniki odwrotne w twoim pliku będą nieporządne). Zobacz moją odpowiedź poniżej na przykład. –

+0

@MarkReed: Nigdy nie zrozumiałem celu '-E', ponieważ jest to domyślne zachowanie Basha dla' echo'. –

Odpowiedz

56

Przetwarzaj linie wewnątrz pętli, a nie za nią. Jeśli naprawdę potrzebujesz pliku w zmiennej:

var=$(<file) 
+0

Czy możesz również wyjaśnić, co się tutaj dzieje? – sbhatla

+2

@sbhatla: Zmienna jest ustawiana na wartość podstawiania poleceń, która zawiera przekierowanie, które odczytuje zawartość pliku. Jest podobny do 'var = $ (plik cat)' ale nie wymaga to tworzenia zewnętrznego pliku wykonywalnego). –

8

Jako inną opcję możesz zbudować tablicę linii. Jeśli używasz bash 4+, można użyć mapfile polecenie wbudowane:

mapfile -t lines <test.file 

Jeśli chcesz być linie wyjściowe, jak również przechowywane mógłby zrobić coś takiego:

mapfile -t lines < <(tee /dev/tty <test.file) 

Następnie "${lines[0]}" będzie pierwszym wierszem pliku, "${lines[1]}" drugim, i tak dalej. ${#lines[@]} będzie liczbą linii; "${lines[@]}" będzie całą tablicą, a "${lines[*]}" będzie liniami połączonymi ze spacjami w jeden duży ciąg.

Dla starszych wersji bash, można zbudować tablicę ręcznie:

lines=() 
while IFS= read -r line 
do 
    printf '%s\n' "$line" 
    lines+=("$line") 
done < test.file 
+1

Łatwiej byłoby napisać to jako 'LINES + = (" linia $ "), prawda? –

+0

Yup. Nauczyłem się trochę przez 4 lata, jak się wydaje. Dobrze wiedzieć.:) –

+0

Nie wątpię w to przez chwilę :) –

10

Inną alternatywą jest użycie piękny mapFile polecenie wbudowane:

mapfile < test.file 
echo "${MAPFILE[@]}" 
+2

Nie ma strony podręcznika dla niego, ale 'help mapfile' poda trochę więcej informacji. Narzędzie domyślnie umieści pierwszą linię w pozycji 0, drugą linię w pozycji 1 i tak dalej. Prawdopodobnie będziesz także chciał użyć go z opcją '-t' (strip newlines). – parvus

+1

Zauważ, że 'mapfile' został wprowadzony w bash 4, więc jest niedostępny w'/bin/bash' na OS X. Który jest prawdopodobnie ostatnim bastionem bash 3, który prawdopodobnie zostanie napotkany w środowisku naturalnym, ale prawdopodobnie również nie zostanie zaktualizowany ze względu na problemy licencyjne z Apple i nową licencją GPL. –

+1

Po uaktualnieniu Apple z Mac OS na Maca dołączono bash 4.4. – DopeGhoti

Powiązane problemy