LINUX.ORG.RU

Команда выводящяя общее начало пути к нескольким директориям/файлам

 , , ,


0

2

Подскажите команду в линуксах или простое решение без лишних зависимостей, перлов и пистонов.

#!/bin/bash

dir1=/tmp/000/111/1/1/1
dir2=/tmp/000/111/1/1/2
dir3=/tmp/000/112/1/1/1

mkdir -p "$dir1"
mkdir -p "$dir2"
mkdir -p "$dir3"

cmd=???
result=$($cmd "$dir1" "$dir2" "$dir3")
echo $result # надо получить /tmp/000/
может кто подскажет более простое решение чем:
cmndir(){
local eop=$(($#+1))
local result=''
local tmps=''
for (( i = 0; i < ${#1}; ++i)); do
local a=${1:$i:1}
for (( n = 2; n < ${eop}; ++n)); do
	local x="x=\${$n:$i:1}"
	eval $x
	[ "x$a" == "x$x" ]  || { echo $result; return 0; }
done
tmps=$tmps$a
[ "x$a" == "x/" ] && result=$tmps
done
echo $result
}

★★★★☆

Последнее исправление: superuser (всего исправлений: 10)
Ответ на: комментарий от superuser

Чем не угодило решение, данное здесь: Команда выводящяя общее начало пути к нескольким директориям/файлам (комментарий)

Там единственное потом результат надо по последнему слешу sed’ом обрезать, если нужны именно каталоги, а не строки, а то если там вложенный каталог, который первый не общий на одну буку начинается, эта буква будет в результате.

CrX ★★★★★
()
Последнее исправление: CrX (всего исправлений: 1)
dron@gnu:~$ dir1=/tmp/000/1/1/1/1
dron@gnu:~$ dir2=/tmp/000/1/1/1/2
dron@gnu:~$ dir3=/tmp/000/2/1/1/1
dron@gnu:~$ gcc main.c
dron@gnu:~$ cmd=./a.out 
dron@gnu:~$ result=$($cmd "$dir1" "$dir2" "$dir3")
dron@gnu:~$ echo $result
/tmp/000/
dron@gnu:~$
#include <stdio.h>
#include <string.h>
#include <limits.h>

int main(int argc, char *argv[])
{
    if(argc < 2)
    {
        printf("Need minimum 2 argumets\n");
        return 1;
    }

    if(argc == 2)
    {
        printf("%s\n",argv[1]);
        return 2;
    }

    char basepath[PATH_MAX]="";
    const size_t  first_len  = strlen(argv[1]);
    for (size_t j = 0; j < first_len; j++ )
    {
        for (size_t i = 2; i < argc; i++  )
        {
            if(argv[1][j] == argv[i][j])
            {
                basepath[j]=argv[1][j];
            }else{
                char * pwd = strrchr(basepath,'/');
                *(pwd+1)='\0';
                printf("%s\n",basepath);
                return 0;
            }
        }
    }
    printf("%s\n",basepath);
    return 0;
}

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от superuser

Ну вот имея /tmp/000/11 просто сделай echo "$result" | sed 's@/[^/]*$@/@', ну. Ну или просто в конец той команды этот ещё один пайп с этим sed’ом добавь. Это обрезать всё после последнего слеша. Если на конце и так слеш, то ничего не обрежется, соответственно.

CrX ★★★★★
()
Последнее исправление: CrX (всего исправлений: 2)
Ответ на: комментарий от superuser

Ну а никак. На баше только циклы большие делать.
ЧатГПТ советует ещё diff и comm

Тут на перле, попробовал

echo "/1/2/3/4/5/6/7/8/9;/1/2/3/4/5/0;/1/2/3/4/59/0/0" | perl -e '@lines=(split /;/, <>);$line=shift @lines;map{chop $line while (! /^\Q$line\E/)} @lines; $line =~ s/[^\/]+$//; print "$line\n";'
/1/2/3/4/

Bad_ptr ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Добавь ещё параметр -d «делимитер», если задан, то обрезать. Такая утилита должна быть в числе стандартных.

superuser ★★★★☆
() автор топика
Последнее исправление: superuser (всего исправлений: 1)
Ответ на: комментарий от superuser

Я уже в трусах, спать ложусь, ком вот выключить подошёл. Сам/завтра если не горт/кто-то вместо меня/вjob =) Просто с разделителем там надо всё по другому делать, а именно токенизацию, а не разбор параметров командой строки. Может даже это лишнее, входящие параметры можно отфильтровать через tr заменив символ текущего разделителя на пробел. Всё я влюльку :3

LINUX-ORG-RU ★★★★★
()

чё так сложно-то и длинно ?

пари, что как-нить ФП короче..1)поделить пути на элемнты, 2)скормить в zip (не архиватор, а комбинатор такой меняет строки и столбцы) и посчитать сколько строк состоят из одинаковых записей

конвеер из трёх частей

PS/ самому лень, уже сплю почти

MKuznetsov ★★★★★
()

🤔

Портянка на awk, для разнообразия:

echo '/tmp/000/111/1/1/1 /tmp/000/111/1/1/2 /tmp/000/112/1/1/1' | xargs -n1 | awk '{n=split($0,a,"/");for(i=1;i<n;i++){if(i in b){if(b[i]!=a[i])b[i]=""}else{b[i]=a[i]}}}END{for(i=2;i<n;i++){if(b[i]=="")break;else printf"/%s",b[i] }print""}'
/tmp/000

iron ★★★★★
()
Ответ на: комментарий от firkax

Не, между

/tmp/000/111/1/1/1 /tmp/000/111/1/1/2 /tmp/000/112/1/1/1

и например

/tmp/000/111/1/1/1,/tmp/000/111/1/1/2,/tmp/000/112/1/1/1

кардинальная разница. Или то что подразумевалось под «делимитер» я не понял.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU
#include <stdio.h>
#include <string.h>
#include <limits.h>

int main(int argc, char *argv[])
{
    if(argc < 2)
    {
        printf("Need minimum 2 argumets\n");
        return 1;
    }

    if(argc == 2)
    {
        printf("%s\n",argv[1]);
        return 2;
    }

    char delimmer[2]="/";
    int  ignore = 0;
    for (int i = 1; i < argc; ++i)
    {
      if(sscanf(argv[i],"-d=%s",delimmer) == 1)
      {
        ignore = i;
        break;
      }
    }

    char basepath[PATH_MAX]="";
    int first_id = (ignore==1)?2:1;
    const size_t  first_len  = strlen(argv[first_id]);

    for (size_t j = 0; j < first_len; j++ )
    {
        for (size_t i = first_id+1; i < argc; i++  )
        {
            if(i == ignore)
            {
                break;
            }
            if(argv[first_id][j] == argv[i][j])
            {
                basepath[j]=argv[first_id][j];
            }else{

                char * pwd = strrchr(basepath,delimmer[0]);
                if(pwd)
                {
                    *(pwd+1)='\0';
                }
                printf("%s\n",basepath);
                return 0;
            }
        }
    }
    printf("%s\n",basepath);
    return 0;
}

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от dataman

Выше сказали до разделителя, и в шапке в конце остаётся /. До этого я вообще думал что разделитель это типа в виде CSV будут подавать пути или ещё как, +1 убрать у pwd и будет без него. Невнятное ТЗ и результат ХЗ :D Да и я второй случай не проверял, просто в 1 примере заменил слеши на : и -d=: в начало параметров сунул и в конец, вот и вся проверка. Ай ну и ладно.

LINUX-ORG-RU ★★★★★
()