Обрезать последние 3 символа строки БЕЗ использования sed, perl и т. Д.

38
задан Community 4 August 2015 в 17:54
поделиться

8 ответов

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

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

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

cat $file | cut -c 1-10
12
ответ дан 27 November 2019 в 02:55
поделиться

Я могу гарантировать вам, что 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 строк менее чем за секунду, что довольно неплохо для того, что выполняется только каждый час.

30
ответ дан 27 November 2019 в 02:55
поделиться

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

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

2
ответ дан 27 November 2019 в 02:55
поделиться

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

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

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

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

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

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

Я думаю, что вам следует использовать sed.

5
ответ дан 27 November 2019 в 02:55
поделиться

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

script | cut -c 1-10

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

script | cut -d ' ' -f 1

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

script | colrm 11
1
ответ дан 27 November 2019 в 02:55
поделиться

Вы можете использовать awk только для вывода первого «поля», если там не будет пробелов (или если они будут, измените разделитель ».

Я поместил поля, которые вы было выше в файл и сделал это

awk '{ print $1 }' < test.txt 
1234567890
1234567891

Не знаю, лучше ли это.

0
ответ дан 27 November 2019 в 02:55
поделиться

что значит не хотите использовать 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
0
ответ дан 27 November 2019 в 02:55
поделиться

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

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

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

echo ${line:0:9}

или

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

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

1
ответ дан 27 November 2019 в 02:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: