Использование обоих утилит GNU с Mac Utils в Bash

Я работаю с графикой очень больших файлов с N количеством соответствующих записей данных. (N варьируется между файлами).

В каждом из этих файлов комментарии автоматически генерируются в начале и в конце файла и хотели бы отфильтровать их перед объединением в один большой набор данных.

К сожалению, я использую MacOSx, где я сталкиваюсь с некоторыми проблемами при попытке удалить последнюю строку файла. Я читал, что наиболее эффективным способом было использование команд head/tail bash для обрезания разделов данных. Поскольку head -n -1 не работает для MacOSx, мне пришлось установить coreutils через homebrew, где прекрасно работает команда ghead. Однако команда,

tail -n+9 $COUNTER/test.csv | ghead -n -1 $COUNTER/test.csv  >> gfinal.csv

не работает. Менее приятным обходным решением было то, что мне пришлось разделить команды, использовать ghead> newfile, а затем использовать tail для newfile> gfinal. К сожалению, это займет некоторое время, так как мне нужно написать новый файл с первым заголовком.

Есть ли обходной путь для включения обоих GNU Utils со стандартными Mac Utils?

Спасибо кевен

2 ответа

Решение

Проблема с вашей командой заключается в том, что вы снова указываете файловый операнд для ghead команда, вместо того, чтобы позволить ему принимать свой ввод от стандартного ввода через канал; это вызывает ghead игнорировать ввод stdin, поэтому первый сегмент трубы фактически игнорируется; просто опустите файловый операнд для ghead команда:

tail -n+9 "$COUNTER/test.csv" | ghead -n -1 >> gfinal.csv

Тем не менее, если вы хотите удалить только последнюю строку, нет необходимости в GNU head - собственный BSD OS X sed Сделаю:

tail -n +9 "$COUNTER/test.csv" | sed '$d' >> gfinal.csv

$ соответствует последней строке, и d удаляет его (это означает, что он не будет выводиться).

Наконец, как отмечает @ghoti в комментарии, вы можете сделать все это, используя sed:

sed -n '9,$ {$!p;}' file

вариант -n говорит sed производить вывод только по явному запросу; 9,$ соответствует всему от линии 9 через (,) конец файла (последняя строка, $), а также {$!p;} печатает (p) каждая строка в этом диапазоне, кроме (!) последний ($).

Я понимаю, что ваш вопрос об использовании head а также tail, но я отвечу так, как если бы вы заинтересовались решением исходной проблемы, а не выясняли, как использовать эти конкретные инструменты для решения проблемы.:)

Один метод с использованием sed:

sed -e '1,8d;$d' inputfile

На этом уровне простоты GNU sed и BSD sed работают одинаково. Наш сценарий sed говорит:

  • 1,8d - удалить строки с 1 по 8,
  • $d - удалить последнюю строку.

Если вы решили сгенерировать подобный скрипт на лету, остерегайтесь цитат; вам придется избежать знака доллара, если вы поставите его в двойные кавычки.

Еще один метод с использованием awk:

awk 'NR>9{print last} NR>1{last=$0}' inputfile

Это работает немного по-другому, чтобы "распознать" последнюю строку, захватить предыдущую строку и напечатать после строки 8, а затем НЕ печатать последнюю строку.

Это awk-решение немного взломано, и, как и решение sed, опирается на тот факт, что вы хотите удалить только ОДНУЮ последнюю строку файла.

Если вы хотите удалить больше строк, чем одну, в нижней части файла, вы, вероятно, захотите сохранить массив, который будет функционировать в виде буферизованного FIFO или скользящего окна.

awk -v striptop=8 -v stripbottom=3 '
  { last[NR]=$0; }
  NR > striptop*2 { print last[NR-striptop]; }
  { delete last[NR-striptop]; }
  END { for(r in last){if(r<NR-stripbottom+1) print last[r];} }
' inputfile

Вы указываете, сколько размешать в переменных. last Массив хранит несколько строк в памяти, печатает из дальнего конца стека и удаляет их по мере их печати. END раздел просматривает все, что остается в массиве, и печатает все, что не запрещено stripbottom,

Другие вопросы по тегам