Mam dwa pliki tekstowe: string.txt i lengths.txt
String.txt:
abcdefghijklmnopqrstuvwxyz
lengths.txt
5
4
10
7
Chcę pobrać plik
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz
Pracuję z około 28 000 wpisów, które różnią się między 200 a 56 000 znaków.
W tej chwili używam:
start=1
end=0
i=0
while read read_l
do
let i=i+1
let end=end+read_l
echo -e ">Entry_$i" >>outfile.txt
echo "$(cut -c$start-$end String.txt)" >>outfile.txt
let start=start+read_l
echo $i
done <lengths.txt
Ale to jest bardzo nieefektywne. Jakieś lepsze pomysły?
linux
shell-script
użytkownik3891532
źródło
źródło
str="$(cat string.txt)"; i=0; while read j; do echo "${file:$i:$j}"; i=$((i+j)); done <length.txt
..seems wystarczająco szybko, jak wykonać tylko skorupy ..{ while read l<&3; do head -c"$l"; echo; done 3<lengths.txt; } <String.txt
.Odpowiedzi:
Możesz to zrobić
Wymaga to wyjaśnienia:
Główną ideą jest użycie
{ head ; } <file
i wywodzi się z niedocenianej odpowiedzi @mikeserv . Jednak w tym przypadku musimy użyć wieluhead
s, więcwhile
wprowadzono pętlę i trochę poprawiono za pomocą deskryptorów plików, aby przejść dohead
danych wejściowych z obu plików (plikString.txt
jako plik główny do przetworzenia, a wierszelength.txt
jako argument do-c
opcji) . Chodzi o to, że korzyści płynące z prędkości powinny wynikać z braku konieczności przeszukiwania zaString.txt
każdym razem, gdy polecenie takie jakhead
lubcut
jest wywoływane.echo
Jest wydrukowanie nowej linii po każdej iteracji.Ile to jest szybsze (jeśli w ogóle), a dodawanie
>Entry_i
między liniami pozostawia się jako ćwiczenie.źródło
read -u 3
do odczytu z deskryptora 3.bash
. Ogromna większość systemów opartych na Linuksie nie zostałabash
zainstalowana (pomyśl Android i inne systemy wbudowane).bash
ponieważ jest to najwolniejsza powłoka ze wszystkich, przejście na bash prawdopodobnie obniży wydajność znacznie bardziej niż niewielki zysk, jaki może przynieść przejście zread <&3
naread -u3
(co w każdym razie będzie nieznaczne w porównaniu z kosztem uruchomienia zewnętrznego polecenia, takiego jakhead
). Przejście nahead
wbudowany ksh93 (i taki, który obsługuje niestandardową-c
opcję) poprawiłby znacznie wydajność.head -c
(dlahead
implementacji, w których dostępna jest ta niestandardowa opcja) jest liczba bajtów, a nie znaki. To by miało znaczenie w wielobajtowych lokalizacjach.Ogólnie rzecz biorąc, nie chcesz używać pętli powłoki do przetwarzania tekstu . Tutaj użyłbym
perl
:To jedno polecenie, które odczytuje (z buforowaniem o wiele bardziej wydajnie niż polecenie powłoki,
read
które odczytuje jeden bajt (lub kilka bajtów dla zwykłych plików) naraz) oba pliki tylko raz (bez przechowywania ich w pamięci), więc jest będzie kilka rzędów wielkości bardziej wydajnych niż rozwiązania uruchamiające zewnętrzne polecenia w pętli powłoki.(dodaj
-C
opcję, jeśli liczby te powinny być liczbami znaków w bieżącym ustawieniu narodowym, a nie liczbą bajtów. W przypadku znaków ASCII, takich jak w twojej próbce, nie będzie to miało znaczenia).źródło
$_
jako parametru wyjściowego i wejściowego doread
, ale zmniejsza liczbę bajtów w skrypcie.bash
, 16 sekund zPATH=/opt/ast/bin:$PATH ksh93
)).bash, wersja 4
wynik
źródło
Co
awk
?Utwórz plik o nazwie
process.awk
z tym kodem:Zapisz i uruchom
awk -f process.awk lengths.txt string.txt
źródło
PROCINFO
nie jest to standardawk
, alegawk
. W takim przypadku wolałbym innągawk
jedyną funkcjęFIELDWIDTHS
:awk -vFIELDWIDTHS="$(tr '\n' ' ' < lengths.txt)" '{for(i=1;i<=NF;i++)print">Entry"i ORS$i}' string.txt