Предполагая, что все данные отформатированы, как в вашем примере, используйте ' cut ', чтобы получить только первый столбец.
cat $file | cut -d ' ' -f 1
или чтобы получить первые 10 символов.
cat $file | cut -c 1-10
Я могу гарантировать вам, что bash
сам по себе не будет быстрее, чем sed
для этой задачи. Запуск внешних процессов в bash
, как правило, плохая идея, но только если вы делаете это часто.
Итак, если вы запускаете процесс sed
для каждой строки ввода, я бы обеспокоился. Но это не так. Вам нужно только запустить один sed
, который сделает всю работу за вас.
Однако вы можете обнаружить, что следующий sed
будет немного быстрее, чем ваша версия:
(whatever) | sed 's/...$//'
Все это удаляет последние три символа в каждой строке, а не заменяет всю строку символом укороченная версия самой себя. Теперь, возможно, более современные движки RE могут оптимизировать вашу команду, но зачем рисковать.
Честно говоря, единственный способ, который я могу придумать быстрее, - это вручную создать собственную программу фильтрации на основе C. И единственная причина, по которой может быть быстрее, чем sed
, заключается в том, что вы можете воспользоваться дополнительными знаниями о ваших потребностях в обработке ( sed
должен учитывать генерализованное шествие, поэтому может быть медленнее из-за этого).
Не забывайте мантру оптимизации: «Измеряйте, не угадайте!»
Если вы действительно хотите делать это по одной строке за раз в bash
(и я все еще утверждаю, что это плохая идея), вы можете использовать:
pax> line=123456789abc
pax> line2=${line%%???}
pax> echo ${line2}
123456789
pax> _
Вы также можете выяснить, действительно ли вам нужно улучшение скорости.Если вы обработаете строки как один большой кусок, вы увидите, что sed
работает достаточно быстро. Введите следующее:
#!/usr/bin/bash
echo This is a pretty chunky line with three bad characters at the end.XXX >qq1
for i in 4 16 64 256 1024 4096 16384 65536 ; do
cat qq1 qq1 >qq2
cat qq2 qq2 >qq1
done
head -20000l qq1 >qq2
wc -l qq2
date
time sed 's/...$//' qq2 >qq1
date
head -3l qq1
и запустите. Вот результат на моем (совсем не очень быстром) ноутбуке R40:
pax> ./chk.sh
20000 qq2
Sat Jul 24 13:09:15 WAST 2010
real 0m0.851s
user 0m0.781s
sys 0m0.050s
Sat Jul 24 13:09:16 WAST 2010
This is a pretty chunky line with three bad characters at the end.
This is a pretty chunky line with three bad characters at the end.
This is a pretty chunky line with three bad characters at the end.
Это 20 000 строк менее чем за секунду, что довольно неплохо для того, что выполняется только каждый час.
Примечание: Этот ответ задуман как шутка, но на самом деле он работает ...
#!/bin/bash
outfile="/tmp/$RANDOM"
cfile="$outfile.c"
echo '#include <stdio.h>
int main(void){int e=1;char c;while((c=getc(stdin))!=-1){if(c==10)e=1;if(c==32)e=0;if(e)putc(c,stdout);}}' >> "$cfile"
gcc -o "$outfile" "$cfile"
rm "$cfile"
cat somedata.txt | "$outfile"
rm "$outfile"
Вы можете заменить cat somedata.txt
на другая команда.
И awk
, и sed
достаточно быстрые, но если вы считаете, что это важно, смело используйте один из следующих вариантов:
Если символы, которые вы хотите удалить, всегда находятся в конце строки
echo '1234567890 *' | tr -d ' *'
Если они могут появляться в любом месте строки, а вы хотите удалить только те, что в конце
echo '1234567890 *' | rev | cut -c 4- | rev
На man-страницах всех команд объясняется, что происходит.
Я думаю, что вам следует использовать sed
.
Если скрипт всегда выводит строки из 10 символов, за которыми следуют 3 дополнительных (другими словами, вам нужны только первые 10 символов), вы можете использовать
script | cut -c 1-10
Если он выводит неопределенное количество непробельных символов, за которым следует пробел, а затем 2 других дополнительных символа (другими словами, вам просто нужно первое поле), вы можете использовать
script | cut -d ' ' -f 1
... как в комментарии majhool ранее. В зависимости от вашей платформы у вас также может быть colrm, который, опять же, будет работать, если строки имеют фиксированную длину:
script | colrm 11
Вы можете использовать awk только для вывода первого «поля», если там не будет пробелов (или если они будут, измените разделитель ».
Я поместил поля, которые вы было выше в файл и сделал это
awk '{ print $1 }' < test.txt
1234567890
1234567891
Не знаю, лучше ли это.
что значит не хотите использовать sed/awk для скорости? sed/awk быстрее, чем цикл while read оболочки для обработки файлов.
$ sed 's/[ \t]*\*$//' file
1234567890
1234567891
$ sed 's/..\*$//' file
1234567890
1234567891
с оболочкой bash
while read -r a b
do
echo $a
done <file
Другой ответ основан на том, что предпоследний символ - пробел. Это работает с (почти) любым символом в этой позиции и делает это "БЕЗ использования sed, или perl, и т.д.":
while read -r line
do
echo ${line:0:${#line}-3}
done
Если ваши строки фиксированной длины, измените echo
на:
echo ${line:0:9}
или
printf "%.10s\n" "$line"
но каждый из них определенно намного медленнее, чем sed
.