Mam plik tekstowy, który wypisuję do zmiennej w moim skrypcie powłoki. Potrzebuję jednak tylko pierwszych 50 znaków.
Próbowałem użyć, cat ${filename} cut -c1-50
ale otrzymuję znacznie więcej niż pierwszych 50 znaków? Może to wynikać z cut
szukania linii (nie w 100% pewności), podczas gdy ten plik tekstowy może być jednym długim ciągiem - to naprawdę zależy.
Czy istnieje narzędzie, do którego mogę wpakować potok, aby uzyskać pierwsze X znaków z cat
polecenia?
|
?cat ${filename} | cut -c1-50
Odpowiedzi:
Zwraca pierwsze 50 bajtów.
Pamiętaj, że polecenie nie zawsze jest realizowane tak samo we wszystkich systemach operacyjnych. W systemach Linux i macOS zachowuje się w ten sposób. W systemie Solaris (11) musisz użyć wersji GNU w / usr / gnu / bin /
źródło
-c
opcji. Pójdę za dd (1) zamiast.GNU coreutils 5.97
) tak.-c
jako prawidłowej opcji, więc jest zdecydowanie zależny od lokalnego środowiska. unix.com/man-page/posix/1/headTwoje
cut
polecenie działa, jeśli do przesyłania danych używasz potoku:Lub unikając bezużytecznego korzystania z kota i czyniąc go nieco bezpieczniejszym:
Zauważ, że powyższe polecenia wypiszą pierwsze 50 znaków (lub bajtów, w zależności od
cut
implementacji) każdej linii wejściowej . Powinien zrobić to, czego oczekujesz, jeśli, jak mówisz, plik ma jedną wielką linię.źródło
Zwraca pierwsze 50 bajtów.
źródło
status=none
flagi.2>/dev/null
Zamiast tego używaj (i odpowiednio cytuj):dd if="$filename" bs=1 count=50 2>/dev/null
(mimo to rozważ użycie wbs=50 count=1
celu zmniejszenia liczby zaangażowanych wywołań systemowych).status=none
gdy używasz Ubuntu 14.04, coreutils 8.21, ale masz rację,2>/dev/null
jeśli używasz wcześniejszej wersji.read()
z 50 bajtów. Jeśli na przykładfile
jest potokiem i dostępnych jest mniej znaków, zwracanych jest mniej bajtów. Aby mieć ekwiwalenthead -c50
, musisz użyć specyficznego dla GNUiflag=fullblock
.Większość odpowiedzi do tej pory zakłada, że 1 bajt = 1 znak, co może nie mieć miejsca, jeśli używasz ustawień regionalnych innych niż ASCII.
Nieco bardziej niezawodny sposób:
Zauważ, że zakłada to:
ksh93
,bash
(lub ostatnizsh
lubmksh
(choć tylko wielo-bajtowego kodowania obsługiwanego przezmksh
UTF-8, a dopiero późniejset -o utf8-mode
)) i wersjahead
, która wspiera-c
(najbardziej zrobić w dzisiejszych czasach, ale nie ściśle standard).locale charmap
ifile -- "$filename"
sprawdź to); jeśli nie, ustaw to za pomocą np.LC_ALL=en_US.UTF-8
)head
, przyjmując najgorszy przypadek UTF-8, w którym wszystkie znaki są zakodowane maksymalnie na 4 bajtach. Powinno to obejmować większość przypadków, o których mogę myśleć.źródło
head
lub inną jego implementację, która dodaje-c
opcję nōn-standard . Ale już potrzebujesz GNU bash. (Uwaga:mksh
tryb UTF-8 mógłby to zrobić dla plików zakodowanych w UTF-8.) Zapytałbym OP, czy wymagają oktetów lub znaków wielobajtowych, po prostu „znaki” to termin niejasny / gerneryczny.$filename
lub$testString
nie zawiera pustej nowej linii lub symboli wieloznacznych lub zaczyna się od-
.${var:offset:length}
Konstrukt używasz tutaj rzeczywiście pochodziksh93
i jest również wspierany przez najnowsze wersjezsh
(zsh
posiada własne$testString[1,50]
). Musisz${testString:0:50}
sięksh93
azsh
jednak.Inny wariant (dla pierwszego wiersza w pliku)
źródło
read
iecho
? Czybash expansion
?grep
(regexp) i tak, użycie powłoki tutaj (wskazówka: pierwsza linia może być duża). (To powiedziawszy, bashizmu nie ma również w POSIX, ale większość pocisków to implementuje.)1. W przypadku plików ASCII, jak lub @DisplayName mówi:
wypisze na przykład pierwsze 50 znaków pliku file.txt.
2. W przypadku danych binarnych użyj
hexdump
do wydrukowania ich jako znaków szesnastkowych:wypisze na przykład pierwsze 50 bajtów pliku.bin.
Zauważ, że bez
-v
opcji pełnejhexdump
zastąpiłoby powtarzające się linie gwiazdką (*
). Zobacz tutaj: https://superuser.com/questions/494245/what-does-an-asterisk-mean-in-hexdump-output/494613#494613 .źródło
Możesz do tego użyć sed, który dość łatwo poradzi sobie z tym problemem
źródło
sed -n -e '1s/^\(.\{50\}\).*/\1/p' ${filename}