Ответ 1
Предполагая, что все данные отформатированы как ваш пример, используйте 'cut', чтобы получить только первый столбец.
cat $file | cut -d ' ' -f 1
или получить первые 10 символов.
cat $file | cut -c 1-10
У меня есть оболочка script, выводящая данные следующим образом:
1234567890 *
1234567891 *
Мне нужно удалить JUST последние три символа "*". Я знаю, что могу сделать это через
(whatever) | sed 's/\(.*\).../\1/'
Но я НЕ хочу использовать sed для скорости. Он всегда будет одним и тем же последним 3 символами.
Любой быстрый способ очистки вывода?
Предполагая, что все данные отформатированы как ваш пример, используйте 'cut', чтобы получить только первый столбец.
cat $file | cut -d ' ' -f 1
или получить первые 10 символов.
cat $file | cut -c 1-10
Вот старомодный трюк Unix для удаления последних трех символов из строки, которая не использует sed OR awk...
> echo 987654321 | rev | cut -c 4- | rev
987654
В отличие от предыдущего примера, использующего 'cut', это не требует знания длины строки.
Я могу гарантировать, что 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 строк в секунду, довольно хорошо для чего-то, что делалось только каждый час.
$ x="can_haz"
$ echo "${x%???}"
can_
Оба awk
и sed
работают довольно быстро, но если вы считаете, что это важно, используйте одно из следующих действий:
Если символы, которые вы хотите удалить, всегда находятся в конце строки
echo '1234567890 *' | tr -d ' *'
Если они могут появляться в любом месте строки, и вы хотите удалить их в конце
echo '1234567890 *' | rev | cut -c 4- | rev
Манифестные страницы всех команд объяснят, что происходит.
Я думаю, что вы должны использовать sed
.
Примечание: Этот ответ несколько предназначен для шутки, но на самом деле он работает...
#!/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
на другую команду.
Вы можете попробовать
(whatever) | while read line; do echo $line | head --bytes -3; done;
head
сам должен быть быстрее, чем sed
или cut
, потому что не существует соответствия регулярных выражений или делителей, но при вызове a для каждой отдельной строки, вероятно, перевешивает это.
Если script всегда выводит строки из 10 символов, за которыми следуют 3 дополнительных (другими словами, вам просто нужны первые 10 символов), вы можете использовать
script | cut -c 1-10
Если он выводит неопределенное количество непространственных символов, за которым следует пробел, а затем еще 2 дополнительных символа (другими словами, вы просто хотите получить первое поле), вы можете использовать
script | cut -d ' ' -f 1
... как в комментарии майхаула ранее. В зависимости от вашей платформы у вас может также быть colrm, который, опять же, будет работать, если строки имеют фиксированную длину:
script | colrm 11
Другой ответ полагается на третий-последний символ, являющийся пространством. Это будет работать с (почти) любым символом в этой позиции и делает это "БЕЗ использования sed или perl и т.д.":
while read -r line
do
echo ${line:0:${#line}-3}
done
Если ваши строки фиксированной длины изменяют значение echo
на:
echo ${line:0:9}
или
printf "%.10s\n" "$line"
но каждый из них определенно намного медленнее, чем sed
.
Вы можете использовать awk только для того, чтобы напечатать первое "поле", если не будет пробелов (или если будет, измените разделитель ".
Я поместил поля, которые у вас были в файл, и сделал это
awk '{ print $1 }' < test.txt
1234567890
1234567891
Я не знаю, лучше ли это.
что вы хотите сказать, не хотите использовать sed/awk для скорости? sed/awk быстрее, чем оболочка, в то время как цикл чтения для обработки файлов.
$ sed 's/[ \t]*\*$//' file
1234567890
1234567891
$ sed 's/..\*$//' file
1234567890
1234567891
с bash оболочкой
while read -r a b
do
echo $a
done <file
Нет необходимости в разрезе или магии, в bash вы можете вырезать строку так:
ORGSTRING="123456"
CUTSTRING=${ORGSTRING:0:-3}
echo "The original string: $ORGSTRING"
echo "The new, shorter and faster string: $CUTSTRING"