Если вам нужна скорость, то использование 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/'
.
sed 's|/[^/]*$||'
Где
/
соответствует буквальному/
[^/]*
соответствует нулю или более не-/
символам $
соответствует концу строки Кажется, вы хотите получить пути к каталогам, содержащим файлы, пути которых хранятся в этих строках.
Ответы, охватывающие основные случаи, уже даны, однако я упомяну несколько моментов, которые стоит рассмотреть в общем случае:
В большинстве систем 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 dirname
8.30 дает:
//foo
///foo
.
.
.
.
foo<0x80>bar
.
/
/
/
Но не будет работать на большинстве других систем, так как:
-d
, -r
и -a
или не -стандартное расширение GNU xargs
xargs
реализаций зависают при вводе не -текста dirname
не требуется принимать более одного аргумента (и немногие делают ). Все еще может произойти сбой, если путь к файлу длиннее, чем аргументы максимального размера для выполняемых команд.
Чтобы получить желаемый результат с помощью awk
, вы можете использовать следующую команду:
awk -F'/' '{print $1"/"$2}' <file_name>
Параметр -F'/'
определяет «/» как разделитель столбцов. Печать $1"/"$2 печатает первый столбец, объединяет "/" и печатает второй столбец.
Вы также можете добиться желаемого результата с помощью обрезки.
cut -d'/' -f1,2 <file_name>
Всем спасибо, ребята,
Наконец это сработало.
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/\/$//'
Предполагая, что ваши иерархические имена сетей хранятся по одному в строке в файле с именем 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_