3

Есть ли простой способ обрезать файл в трубе? В частности, я хочу нарезать последние четыре байта файла перед передачей его в другой процесс.

В идеале я мог бы написать что-то вроде:

cat input.txt | some-process | truncate --size=-4 | another-process > output.txt

но похоже, что команда truncate работает только "на месте" с файлом на диске.

6 ответов6

4

Это как если бы я сказал вам поднять руку, как только произнесу четвертое от последнего слова, которое я собираюсь сказать. Я не собираюсь говорить вам заранее, сколько слов я собираюсь сказать.

Труба - это поток. Его данные не имеют размера, у него есть только операции по извлечению из него следующего элемента и / или вставке в него элемента, и результатом является либо фрагмент данных, либо сигнал о том, что данных больше нет.

Таким образом, если вы сначала не извлечете все данные из потока, не поместите их в буфер, не подсчитаете их длину, не перемотаете поток и затем не получите на четыре элемента меньше, это невозможно сделать.

РЕДАКТИРОВАТЬ: мне нужно делать больше продумывать вещи, вместо того, чтобы придумывать умные аналогии :) Поток не говорит "немедленно остановить меня n элементов до последнего", а скорее "передать все элементы, кроме последнего n", и путем буфер из только n элементов, и ожидание, пока первые n элементов не будут получены, прежде чем передать первый, возможно. Очевидно, что это не сработает в таких ситуациях, как телекоммуникации, когда вы хотите, чтобы данные отправлялись сразу после их получения, как вы могли бы, если бы вам нужны были первые n элементов. И я предполагаю, что truncate не делает это таким образом.

(попытка понизить самооценку -1)

3

Я чувствую себя глупо после написания этого скрипта Python.

Существует встроенный в командной оболочке head , чтобы сделать это:

cat input.txt | some-process | head --bytes=-4 | another-process > output.txt

Редактировать: команда GNU head имеет концептуально похожую реализацию (т.е. эффективную для памяти) с моей реализацией Python ниже. Одно из отличий состоит в том, что он округляет размер циклического буфера (N , количество исключенных байтов) до кратного некоторого стандартного размера буфера.

1

sed может работать на последней строчке. Это предполагает, что последние 4 символа находятся в одной строке:

printf "%s\n" abcdef ghijkl mnopqr | sed '$s/....$//'

выходы

abcdef
ghijkl
mn
0

Я удивлен, что никто не упомянул dd .

Это будет читать первые 1024 байта ввода:

$ dd if=inputfile of=truncated_file count=1024

Это пропустит первые 2048 байтов ввода:

$ dd if=inputfile of=truncated_file skip=2048

Удаляя if и / или параметра (ов), of будет читать из STDIN и записывать в STDOUT. Это означает, что вы можете делать такие вещи:

$ cat input.txt | dd count=1024 | another-process > output.txt

В зависимости от того, какую версию dd вы используете, вы можете указать единицы измерения для count и skip параметры (см. Man-страницу для более подробной информации).

0

Я не смог найти никаких встроенных команд оболочки, чтобы сделать это, поэтому я предполагаю, что это означает, что не существует «однострочного» решения. Тем не менее, я смог написать скрипт Python, чтобы сделать то, что мне нужно:

#!/usr/bin/env python
'''
Usage:
pipetruncate.py <N>

Truncates a stream in a pipe at N bytes before the EOF.
Uses memory proportional to N.
'''

import sys

buffer_length = int(sys.argv[1])
circular_buffer = [0]*buffer_length
count = 0
while True:
    ch = sys.stdin.read(1)
    if not len(ch): # EOF
        break

    index = count % buffer_length
    nextchar = circular_buffer[index]
    circular_buffer[index] = ch

    count += 1
    if count > buffer_length:
        sys.stdout.write(nextchar)

sys.stdout.close()

Тогда я призываю

cat input.txt | some-process | ./pipetruncate.py 4 | another-process > output.txt

0

Потратил часть утра на написание скрипта на python. Конечно, вам лучше использовать свою "голову" вместо того, чтобы писать больше кода. В любом случае, вот моя версия. Это ужасно, но я думаю, что это мой первый скрипт на Python:

#!/usr/bin/python

# stream_trunc: cut the last n bits of a stream

import sys

if len(sys.argv) <> 2:
    print 'Usage: ' + sys.argv[0] + ' <number>'
    exit(1)

num = sys.argv[1]

if num.isdigit() != True:
    print 'Argument should be a number'
    print 'Usage: ' + sys.argv[0] + ' <number>'
    exit(1)

n = int(num)
buf = sys.stdin.read(n)
c = sys.stdin.read(1)

while c != '':
    sys.stdout.write(buf[0])
    buf = buf[1:] + c
    c = sys.stdin.read(1)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .