2013-04-01 20 views

Odpowiedz

15

Oprócz odpowiedzi udzielonych przez fedorqui i Kent, można również użyć jednego sed polecenie:

#! /bin/sh 
filename=$1 
firstline=$2 
lastline=$3 

# Basics of sed: 
# 1. sed commands have a matching part and a command part. 
# 2. The matching part matches lines, generally by number or regular expression. 
# 3. The command part executes a command on that line, possibly changing its text. 
# 
# By default, sed will print everything in its buffer to standard output. 
# The -n option turns this off, so it only prints what you tell it to. 
# 
# The -e option gives sed a command or set of commands (separated by semicolons). 
# Below, we use two commands: 
# 
# ${firstline},${lastline}p 
# This matches lines firstline to lastline, inclusive 
# The command 'p' tells sed to print the line to standard output 
# 
# ${lastline}q 
# This matches line ${lastline}. It tells sed to quit. This command 
# is run after the print command, so sed quits after printing the last line. 
# 
sed -ne "${firstline},${lastline}p;${lastline}q" < ${filename} 

Lub, aby uniknąć jakichkolwiek zewnętrznych narzędziowych, jeśli używasz najnowszej wersji bash (lub zsh):

#! /bin/sh 

filename=$1 
firstline=$2 
lastline=$3 

i=0 
exec <${filename} # redirect file into our stdin 
while read ; do # read each line into REPLY variable 
    i=$(($i + 1)) # maintain line count 

    if [ "$i" -ge "${firstline}" ] ; then 
    if [ "$i" -gt "${lastline}" ] ; then 
     break 
    else 
     echo "${REPLY}" 
    fi 
    fi 
done 
+0

@ user2232423 Wszystkie polecenia Unix mają standardowe wejście (stdin) i standardowe wyjście (stdout). Polecenia 'sed',' awk' i wiele innych (w tym 'head' i' tail') odczytują ich wejście ze stdin, przetwarzają je i zapisują wyniki na standardowe wyjście. Domyślnie stdin/stdout są dołączone do terminala. Używając przekierowania (np .: 'COMMAND < FILE1 > FILE2'), możesz ustawić stdin dla' COMMAND', aby odczytać z 'FILE1' i stdout, aby zapisać do' FILE2'. Jest to fundamentalne dla Uniksa; możesz zapoznać się z samouczkiem (http://www.ceri.memphis.edu/computer/docs/unix/bshell.htm) lub książką, aby uzyskać lepsze zrozumienie. – sfstewman

+0

@ user2232423 Ponadto zarówno 'awk', jak i' sed' oferują dużą moc do przetwarzania tekstu. Jeśli zamierzasz spędzać dużo czasu w Uniksie, te dwa polecenia (plus 'grep') będą bardzo, bardzo użyteczne. Warto się uczyć, choć łatwiej się ich nauczyć w małych kawałkach na raz. Możesz znaleźć [sed & awk] (http://shop.oreilly.com/product/9781565922259.do) jako przydatną książkę. – sfstewman

+0

Dzięki, świetna rada. Mam kilka rzeczy, których nie jestem pewien, np. W jaki sposób sed dopasowuje linie z kodem tak prostym, jak $ {firstline}, $ {lastline} p <<, co właściwie tam się dzieje? –

4

próbować ten jeden-liner:

awk -vs="$begin" -ve="$end" 'NR>=s&&NR<=e' "$f" 

w powyższej linii:

$begin is your $2 
$end is your $3 
$f is your $1 
+0

Preferuję utrzymywać to proste za pomocą głowy i ogona, –

+2

@ user2232423 ok, możesz wybrać rozwiązanie, które najbardziej Ci odpowiada.mamy inną definicję "prostego". ** a) ** potrzebujesz dwóch procesów z głową i ogonem. awk to tylko jeden proces. ** b) ** awk może również zakończyć przetwarzanie po osiągnięciu "$ 3" (nie zrobiłem tego w mojej odpowiedzi), jeśli masz plik potworów. ** c) ** awk może walidować twoje $ 2 $ 3, np. jeśli $ 2> $ 3, to nie przetwarza w ogóle pliku. musisz napisać dodatkowy skrypt dla swojej głowy/ogona. awk jest prostsze, prawda? – Kent

+0

Ok, czy mógłbyś rozbić swój liniowiec i wyjaśnić? –

22
head -n XX # <-- print first XX lines 
tail -n YY # <-- print last YY lines 

Jeśli chcesz wiersze z 20 do 30, co oznacza, że ​​chcesz 11 linii zaczynając od 20 i kończąc na 30:

head -n 30 file | tail -n 11 
# 
# first 30 lines 
#     last 11 lines from those previous 30 

Oznacza to, że po pierwsze uzyskać pierwsze 30 linii, a następnie wybrać ostatni 11 (czyli 30-20+1).

Więc w kodzie byłoby:

head -n $3 $1 | tail -n $(($3-$2 + 1)) 

podstawie firstline = $2, lastline = $3, filename = $1

head -n $lastline $filename | tail -n $(($lastline -$firstline + 1)) 
+0

może użyć 'tail -n + $ 2' zamiast –

+0

@ AurélienOoms nie wiesz co dokładnie masz na myśli. W takim przypadku, czy chcesz tego użyć? Po "głowie" zakładam. – fedorqui

+0

Miałem na myśli 'head -n $ 3 $ 1 | tail -n + 2 $ ". –

4

Zapisz jako "script.sh":

#!/bin/sh 

filename="$1" 
firstline=$2 
lastline=$3 
linestoprint=$(($lastline-$firstline+1)) 

tail -n +$firstline "$filename" | head -n $linestoprint 

jest NO ERROR POSTĘPOWANIE (dla uproszczenia), więc trzeba zadzwonić skrypt w następujący sposób:

./script.sh yourfile.t xt Firstline lastline

$ ./script.sh yourfile.txt 5 10 

Jeśli potrzebne jest tylko linia "10" od yourfile.txt:

$ ./script.sh yourfile.txt 10 10 

Proszę się upewnić, że: (Firstline> 0) i (lastline> 0) i (firstline < = lastline)

+0

Klucz '+' w 'tail -n + $ firstline' jest kluczem. – palindrom