Как удалить последний символ с косой чертой в unix?

Если вам нужна скорость, то использование PCRE (или другой, возможно, более быстрой библиотеки регулярных выражений )из C позволит использовать как регулярное выражение, так и проверку наличия новой строки. Недостатки :новый код для сопровождения и отладки, время на повторную -реализацию частей grepили perlв зависимости от сложности выражения или использования таких функций, как --only-matching.

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <pcre.h>
#define MAX_OFFSET 3

int main(int argc, char *argv[])
{
    // getline
    char *line = NULL;
    size_t linebuflen = 0;
    ssize_t numchars;
    // PCRE
    const char *error;
    int erroffset, rc;
    int offsets[MAX_OFFSET];
    pcre *re;

    if (argc < 2) errx(1, "need regex");
    argv++;
    if ((re = pcre_compile(*argv, 0, &error, &erroffset, NULL)) == NULL)
        err(1, "pcre_compile failed at offset %d: %s", erroffset, error);

    while ((numchars = getline(&line, &linebuflen, stdin)) > 0) {
        if (line[numchars-1] != '\n') break;
        rc = pcre_exec(re, NULL, line, numchars, 0, 0, offsets, MAX_OFFSET);
        if (rc > 0) fwrite(line, numchars, 1, stdout);
    }
    exit(EXIT_SUCCESS);
}

Это примерно на 49% быстрее, чем perl -ne 'print if /.../ && /\n\z/'.

-2
23.05.2020, 18:35
5 ответов
sed 's|/[^/]*$||'

Где

  • /соответствует буквальному/
  • [^/]*соответствует нулю или более не-/символам
  • $соответствует концу строки
6
18.03.2021, 23:33

Кажется, вы хотите получить пути к каталогам, содержащим файлы, пути которых хранятся в этих строках.

Ответы, охватывающие основные случаи, уже даны, однако я упомяну несколько моментов, которые стоит рассмотреть в общем случае:

  • В большинстве систем Unix пути к файлам могут состоять из любой последовательности байтов, кроме 0. Это включает в себя байт, используемый для представления символа новой строки. Это может включать последовательность байтов, которые не образуют допустимый символ, который может быть длиннее, чемLINE_MAX(стандартная константа (, но значение которой остается на усмотрение каждой реализации ), которая определяет максимальное количество байтов текста строки могут иметь, если вы хотите быть уверенным, что текстовые утилиты будут корректно работать с ними ).

    Таким образом, здесь этот входной формат не может выражать список путей к файлам (, таких как те, которые содержат символы новой строки ), и даже для списка путей к файлам без символов новой строки и в LINE _МАКС. байтах вы необходимо запустить текстовые утилиты в локали C, чтобы убедиться, что они справятся с произвольными значениями байтов.

  • /— разделитель компонентов пути, но

      Только
    • /является особым и представляет файл корневого каталога. Не существует каталога , содержащего этот файл, хотя по соглашению мы обычно говорим, что его родительский каталог — это он сам. В любом случае, вам придется обращаться с ним по-особому, если он может появиться на входе.
    • последовательности из более чем одного /действуют как один, foo//barсовпадает с foo/bar.
    • за исключением начала последовательности из ровно двух //.Где ///fooсовпадает с /foo, но //fooне обязательно совпадает с /foo(, а в некоторых системах это не так ). В более общем случае мы мало что можем сказать о файлах, начинающихся с //. Например, каждый компонент с разделителями /может даже не быть каталогами , поэтому в этом случае трудно решить, что делать.
  • fooтакже является относительным путем. Его родительский каталог — это ., а не пустая строка .

  • .и ..являются скорее инструментами для обхода каталогов, чем реальными файлами. Но они относятся к реальным файлам. Итак, что мы должны сообщить для их имени каталога или родительского каталога(..и ../..соответственно? Или .как для других/-менее относительных путей? ).

  • foo/bar/или foo/bar//аналогичны foo/bar, по крайней мере, если foo/barсам по себе является каталогом, поэтому его родительский каталог должен быть foo.

Менее прирученный вход может быть:

//foo/bar
///foo//bar//
foo
foo//
.
../
foo<0x80>bar/baz<0x81>
--foo
/
//
///

Одним из способов решения проблем было бы довериться команде dirname, которая предназначена для этого, и принять ее решение, когда нет ни одного очевидного.

Трудная часть переносимости состоит в том, чтобы перейти от этой строки -на основе ввода к аргументам в dirname.

В системе GNU это можно сделать с помощью:

xargs -rd '\n' -a your-file dirname --

Что с GNU dirname8.30 дает:

//foo
///foo
.
.
.
.
foo<0x80>bar
.
/
/
/

Но не будет работать на большинстве других систем, так как:

  • -d, -rи -aили не -стандартное расширение GNU xargs
  • несколько xargsреализаций зависают при вводе не -текста
  • dirnameне требуется принимать более одного аргумента (и немногие делают ).

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

6
18.03.2021, 23:33

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

awk -F'/' '{print $1"/"$2}' <file_name>

Параметр -F'/'определяет «/» как разделитель столбцов. Печать $1"/"$2 печатает первый столбец, объединяет "/" и печатает второй столбец.

Вы также можете добиться желаемого результата с помощью обрезки.

cut -d'/' -f1,2 <file_name>
1
18.03.2021, 23:33

Всем спасибо, ребята,

Наконец это сработало.

awk -F "/" '{$NF=""; print $0}' instance1/instance2/instance3/and_gate_inst/and_gate/a_pin | sed 's/ /\//g' | sed 's/\/$//'
awk -F "/" '{$NF=""; print $0}' instance1/instance2/or_gate/b_pin | sed 's/ /\//g' | sed 's/\/$//'
-1
18.03.2021, 23:33

Предполагая, что ваши иерархические имена сетей хранятся по одному в строке в файле с именем netnames.txt, мы можем запустить следующий tclкод, чтобы подключить шлюз к этой сети.

tclsh - netnames.txt <<\_TCL_
set fh [open [lindex $argv 1]]
while { [gets $fh line] >= 0 } {
puts [join [lreplace [split $line /] end end] /]
}
close $fh
_TCL_
0
18.03.2021, 23:33

Теги

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