Próbuję uzyskać określoną linię z pliku tekstowego.
Do tej pory w Internecie widziałem tylko rzeczy takie jak sed (mogę używać tylko sh -not bash lub sed lub czegoś podobnego). Muszę to zrobić tylko przy użyciu podstawowego skryptu powłoki.
cat file | while read line
do
#do something
done
Wiem, jak iterować po liniach, jak pokazano powyżej, ale co, jeśli potrzebuję tylko uzyskać zawartość określonej linii
cat
porządku, alesed
nie jest? To nie ma sensu.cat
. Och ... uroczycat
!Odpowiedzi:
sed:
awk:
źródło
5!d
oznacza usuń wszystkie linie z wyjątkiem 5. shell var jest możliwe, potrzebujesz podwójnych cudzysłowów.sed -n 5p
wydaje się to bardziej logiczne do zapamiętania dla początkujących, ponieważ-n
oznacza "domyślnie brak wyjścia" ip
oznacza "drukuj" i nie ma potencjalnie mylącej wzmianki o usuwaniu (kiedy ludzie mówią o plikach, usuwanie linii ma tendencję do znaczy coś innego).-n '5p'
działa też w przypadku tego problemu. Różnica polega na tym,5!d
że możesz dodać,-i
aby zapisać zmianę z powrotem do pliku. jednakże,-n 5p
co do tegosed -n '5p' f > f2&& mv f2 f
znowu, zgadzam się z pańską opinią na to pytanie.Zakładając, że
line
jest to zmienna, która przechowuje wymagany numer linii, jeśli możesz użyćhead
itail
, to jest całkiem proste:Jeśli nie, to powinno działać:
źródło
-eq
porównanie dotyczy liczb całkowitych, więc potrzebny jest numer wiersza, a nie zawartość wiersza ($line
). Należy to naprawić, definiując np.want=5
Przed pętlą, a następnie używając-eq
porównania na$want
. [przeniesione z odrzuconej edycji]Możesz użyć
sed -n 5p file
.Możesz również uzyskać zakres, np
sed -n 5,10p file
.źródło
Najlepsza metoda wykonania
Ponieważ
sed
przestaje czytać wszystkie wiersze po piątejZaktualizuj eksperyment pana Rogera Duecka
źródło
sed -n 5q
sed
przestaje czytać jakiekolwiek wiersze po piątej.sed -n 1p /usr/share/dict/words
ised '1q;d' /usr/share/dict/words
używająctime
polecenia; pierwsza trwała 0,043 s, druga tylko 0,002 s, więc użycie „q” zdecydowanie poprawia wydajność!Jeśli na przykład chcesz uzyskać wiersze od 10 do 20 pliku, możesz użyć każdej z tych dwóch metod:
lub
p
w powyższym poleceniu oznacza drukowanie.Oto, co zobaczysz:
źródło
Standardowym sposobem na to jest użycie narzędzi zewnętrznych. Niedopuszczanie do używania zewnętrznych narzędzi podczas pisania skryptu powłoki jest absurdalne. Jeśli jednak naprawdę nie chcesz używać narzędzi zewnętrznych, możesz wydrukować wiersz 5 z:
Zwróć uwagę, że spowoduje to wydrukowanie linii logicznej 5. Oznacza to, że jeśli
input-file
zawiera kontynuacje linii, zostaną one policzone jako pojedynczy wiersz. Możesz zmienić to zachowanie, dodając-r
do polecenia odczytu. (Co jest prawdopodobnie pożądanym zachowaniem).źródło
$((++i))
wydaje się być bashizmem; jeśli OP jest ograniczony w korzystaniu z zewnętrznych narzędzi, nie zakładałbym, że będą mieli dostęp do czegoś więcej niż zwykłego/bin/sh
++
przyrostów jest specjalnie oznaczona jako opcjonalna).$((i+=1))
działa również w Dash.$(($i+1))
to proste obejście, o którym myślałem.Równolegle z odpowiedzią Williama Pursella , oto prosta konstrukcja, która powinna działać nawet w oryginalnej powłoce Bourne'a v7 (a więc także w miejscach, w których Bash nie jest dostępny).
Zwróć także uwagę na optymalizację
break
wyjścia z pętli, gdy otrzymaliśmy szukaną linię.źródło
Nie podobała mi się żadna z odpowiedzi.
Oto jak to zrobiłem.
źródło
Łatwo z Perlem! Jeśli chcesz pobrać linie 1, 3 i 5 z pliku, powiedz / etc / passwd:
źródło
seq 5 | perl -ne 'print if $. ~~ [1, 4, 5]'
ale smartmatch jest eksperymentalny i odradza się jego używaniaźródło
sed -n 5p
, które oczywiście można jeszcze zoptymalizować do czegoś takiegosed -n '5!d;p;q'