Обрезать последние 3 символа строки БЕЗ использования sed, perl и т. Д. - PullRequest
38 голосов
/ 24 июля 2010

У меня есть сценарий оболочки, выводящий данные, подобные этому:

1234567890  *
1234567891  *

Мне нужно просто удалить последние три символа "*".Я знаю, что могу сделать это через

(whatever) | sed 's/\(.*\).../\1/'

Но я не хочу использовать sed для скорости.Это будут всегда те же самые последние 3 символа.

Какой-нибудь быстрый способ очистить вывод?

Ответы [ 12 ]

164 голосов
/ 03 мая 2011

Вот старомодный трюк Unix для удаления последних 3 символов из строки, которая не использует sed или awk ...

> echo 987654321 | rev | cut -c 4- | rev

987654

В отличие от более раннего примера, использующего 'cut', это не требует знания длины строки.

30 голосов
/ 24 июля 2010

Я могу гарантировать вам, что только bash не будет быстрее, чем sed для этой задачи.Запуск внешних процессов в bash - это, как правило, плохая идея, но только если вы делаете это много.

Итак, если вы запускаете процесс sed для каждой строкиВаш вклад, я буду обеспокоен.Но ты не.Вам нужно только запустить one 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.

Это 20000 строк в секунду, довольно хорошо для того, что выполняется только каждый час.

12 голосов
/ 24 июля 2010

Предполагая, что все данные отформатированы, как в вашем примере, используйте ' cut ', чтобы получить только первый столбец.

cat $file | cut -d ' ' -f 1  

или получить первые 10 символов.

cat $file | cut -c 1-10
11 голосов
/ 27 февраля 2014
$ x="can_haz"
$ echo "${x%???}"
can_
5 голосов
/ 24 июля 2010

Оба awk и sed достаточно быстрые, но если вы считаете, что это имеет значение, не стесняйтесь использовать один из следующих вариантов:

Если символы, которые вы хотите удалить, всегда находятся наконец строки

echo '1234567890  *' | tr -d ' *'

Если они могут появляться в любом месте строки, и вы хотите удалить их только в конце

echo '1234567890  *' | rev | cut -c 4- | rev

Справочные страницы всех команд объяснят, что происходит.

Я думаю, что вы должны использовать sed, хотя.

2 голосов
/ 31 января 2014

Вы можете попробовать

(whatever) | while read line; do echo $line | head --bytes -3; done;

head само по себе должно быть быстрее, чем sed или cut, потому что нет соответствия регулярному выражению или разделителю, но вызов a для каждой отдельной строки, вероятно, перевесит это.

2 голосов
/ 24 июля 2010

Примечание: Этот ответ несколько шутка, но он действительно работает ...

#!/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 другой командой.

1 голос
/ 12 июля 2016

Нет необходимости в срезе или магии, в bash вы можете обрезать строку следующим образом:

  ORGSTRING="123456"
  CUTSTRING=${ORGSTRING:0:-3}
  echo "The original string: $ORGSTRING"
  echo "The new, shorter and faster string: $CUTSTRING"

См. http://tldp.org/LDP/abs/html/string-manipulation.html

1 голос
/ 24 июля 2010

Другой ответ основан на том, что третий-последний символ является пробелом. Это будет работать с (почти) любым символом в этой позиции и делает это «БЕЗ использования sed, или perl и т. Д.»:

while read -r line
do
    echo ${line:0:${#line}-3}
done

Если ваши строки имеют фиксированную длину, измените echo на:

echo ${line:0:9}

или

printf "%.10s\n" "$line"

но каждый из них определенно намного медленнее, чем sed.

1 голос
/ 24 июля 2010

Если скрипт всегда выводит строки из 10 символов, за которыми следуют 3 дополнительных (другими словами, вам просто нужны первые 10 символов), вы можете использовать

script | cut -c 1-10

Если выводится неопределенное количество непробельных символов, затем пробел, а затем еще 2 дополнительных символа (другими словами, вам просто нужно первое поле), вы можете использовать

script | cut -d ' ' -f 1

... как и в комментариях майшколы ранее. В зависимости от вашей платформы, вы также можете иметь colrm, который, опять же, будет работать, если строки имеют фиксированную длину:

script | colrm 11
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...