首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在不展开符号链接的情况下对相对路径进行符号链接

在不展开符号链接的情况下对相对路径进行符号链接
EN

Stack Overflow用户
提问于 2015-02-18 08:50:28
回答 2查看 242关注 0票数 0

在linux上使用C语言时,我有两个字符数组,其中包含相对于cwd的路径。假设它们是"foo/txt""bar/txt"。我想创建一个从第一个指向第二个的符号链接。问题是,如果我转到symlink("bar/txt", "foo/txt")foo/txt将查找不存在的foo/bar/txt。我可以将".."添加到目标路径的开头,但我不知道源字符串中包含了多少个目录级别

使问题更加复杂的是,目标本身可能是一个符号链接,而我不想遍历它,如果我使用realpath(),可能会发生这种情况。一旦创建了我想要的链接,目录结构可能如下所示(对我来说,生成的符号链接是相对的还是绝对的并不重要):

代码语言:javascript
复制
/somecwd/foo/txt -> ../bar/txt
/somecwd/bar/txt -> ../baz/txt
/somecww/baz/txt

有人知道我会怎么做吗?任何帮助都是非常感谢的。

编辑:理想情况下,即使给我的路径是绝对路径,这也是可行的

EN

回答 2

Stack Overflow用户

发布于 2015-02-18 14:08:44

使用symlink()函数,BSD (Mac )手册页显示:

int symlink(const char *path1,const char *path2);

描述

创建指向path1的符号链接path2 (path2是创建的文件名,path1是创建符号链接时使用的字符串)。这两个名称都可以是任意路径名;文件不需要在同一文件系统上。

请注意,您指定为path1的内容将作为符号链接的内容逐字使用。因此,要使符号链接准确,您必须获得正确的相对路径。也就是说,作为path1传递的名称必须是相对于path2的正确名称。

换句话说,您不能完全避免映射名称的过程,以及随之而来的所有困难。

我有一个Perl脚本relpath,它是我从对Convert absolute path into relative path given a current directory的回答和来自comp.unix.shell的一条相当古老的新闻组消息拼凑而成的。将其中的一些代码转换为C语言并不是人类的智慧所在。事实上,这肯定已经被做了无数次了。困难将是找到代码。

更新路径

代码语言:javascript
复制
#!/usr/bin/env perl
#
# @(#)$Id: relpath.pl,v 1.4 2014/12/08 18:23:17 jleffler Exp $
#
# Usage:    relpath source target [...]
#
# Purpose:  Print relative path of target w.r.t. source
#
# Based loosely on code from:
# http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2005-10/1256.html
# Via: https://stackoverflow.com/questions/2564634

use strict;
use warnings;
use File::Basename;
use Cwd qw(realpath getcwd);

if (scalar @ARGV < 2)
{
    my $arg0 = basename($0, ".pl");
    die "Usage: $arg0 from to [...]\n"
}

my $pwd;
my $verbose = 0;

# Fettle filename so it is absolute.
# Deals with '//', '/./' and '/../' notations, plus symlinks.
# The realpath() function does the hard work if the path exists.
# For non-existent paths, the code does a purely textual hack.
sub resolve
{
    my($name) = @_;
    my($path) = realpath($name);
    if (!defined $path)
    {
        # Path does not exist - do the best we can with lexical analysis
        # Assume Unix - not dealing with Windows.
        $path = $name;
        if ($name !~ m%^/%)
        {
            $pwd = getcwd if !defined $pwd;
            $path = "$pwd/$path";
        }
        $path =~ s%//+%/%g;     # Not UNC paths.
        $path =~ s%/$%%;        # No trailing /
        $path =~ s%/\./%/%g;    # No embedded /./
        # Try to eliminate /../abc/
        $path =~ s%/\.\./(?:[^/]+)(/|$)%$1%g;
        $path =~ s%/\.$%%;      # No trailing /.
        $path =~ s%^\./%%;      # No leading ./
        # What happens with . and / as inputs?
    }
    return($path);
}

sub print_result
{
    my($source, $target, $relpath) = @_;
    if ($verbose)
    {
        print "source  = $ARGV[0]\n";
        print "target  = $ARGV[1]\n";
        print "relpath = $relpath\n";
    }
    else
    {
        print "$relpath\n";
    }
}

# Nasty!
my($source) = resolve($ARGV[0]);
my(@source) = split '/', $source;
shift @ARGV;

sub relpath
{
    my($name) = @_;
    my($target) = resolve($name);
    print_result($source, $target, ".") if ($source eq $target);

    # Split!
    my(@target) = split '/', $target;

    my $count = scalar(@source);
       $count = scalar(@target) if (scalar(@target) < $count);
    my $relpath = "";
    my $i;

    # Both paths are absolute; Perl splits an empty field 0.
    for ($i = 1; $i < $count; $i++)
    {
        last if $source[$i] ne $target[$i];
    }

    for (my $s = $i; $s < scalar(@source); $s++)
    {
        $relpath = "$relpath/" if ($s > $i);
        $relpath = "$relpath..";
    }
    for (my $t = $i; $t < scalar(@target); $t++)
    {
        $relpath = "$relpath/" if ($relpath ne "");
        $relpath = "$relpath$target[$t]";
    }

    print_result($source, $target, $relpath);
}

foreach my $target (@ARGV)
{
    relpath($target);
}

test.relpath

注意:这需要relpath.pl,而不仅仅是relpath

代码语言:javascript
复制
#!/bin/ksh
#
# @(#)$Id: test.relpath.sh,v 1.1 2010/04/25 15:19:20 jleffler Exp $
#
# Test relpath Perl script fairly exhaustively
# BUG: should include expected answers!

sed 's/#.*//;/^[    ]*$/d' <<! |

/home/part1/part2 /home/part1/part3
/home/part1/part2 /home/part4/part5
/home/part1/part2 /work/part6/part7
/home/part1       /work/part1/part2/part3/part4
/home             /work/part2/part3
/                 /work/part2/part3/part4

/home/part1/part2 /home/part1/part2/part3/part4
/home/part1/part2 /home/part1/part2/part3
/home/part1/part2 /home/part1/part2
/home/part1/part2 /home/part1
/home/part1/part2 /home
/home/part1/part2 /

/home/part1/part2 /work
/home/part1/part2 /work/part1
/home/part1/part2 /work/part1/part2
/home/part1/part2 /work/part1/part2/part3
/home/part1/part2 /work/part1/part2/part3/part4

home/part1/part2 home/part1/part3
home/part1/part2 home/part4/part5
home/part1/part2 work/part6/part7
home/part1       work/part1/part2/part3/part4
home             work/part2/part3
.                work/part2/part3

home/part1/part2 home/part1/part2/part3/part4
home/part1/part2 home/part1/part2/part3
home/part1/part2 home/part1/part2
home/part1/part2 home/part1
home/part1/part2 home
home/part1/part2 .

home/part1/part2 work
home/part1/part2 work/part1
home/part1/part2 work/part1/part2
home/part1/part2 work/part1/part2/part3
home/part1/part2 work/part1/part2/part3/part4

!

{
echo "Relative paths (source, target, relative path)"
while read source target
do
    echo "$source $target $(${PERL:-perl} relpath.pl $source $target)"
done |
awk '{ printf("%-20s   %-30s   %s\n", $1, $2, $3); }'
}

输出示例

请注意,如果/home/part1/part2是一个目录,或者假设它是一个目录,则第一个相对路径../part3是正确的。这段代码在解释输出时需要特别小心。注意,symlink()系统调用不要求path1名称引用现有的文件或目录(但相比之下,path2一定不能引用现有的文件或目录,尽管只有叶元素不能存在;以前的所有目录都必须存在)。

代码语言:javascript
复制
Relative paths (source, target, relative path)
/home/part1/part2      /home/part1/part3                ../part3
/home/part1/part2      /home/part4/part5                ../../part4/part5
/home/part1/part2      /work/part6/part7                ../../../work/part6/part7
/home/part1            /work/part1/part2/part3/part4    ../../work/part1/part2/part3/part4
/home                  /work/part2/part3                ../work/part2/part3
/                      /work/part2/part3/part4          work/part2/part3/part4
/home/part1/part2      /home/part1/part2/part3/part4    part3/part4
/home/part1/part2      /home/part1/part2/part3          part3
/home/part1/part2      /home/part1/part2                .
/home/part1/part2      /home/part1                      ..
/home/part1/part2      /home                            ../..
/home/part1/part2      /                                ../../..
/home/part1/part2      /work                            ../../../work
/home/part1/part2      /work/part1                      ../../../work/part1
/home/part1/part2      /work/part1/part2                ../../../work/part1/part2
/home/part1/part2      /work/part1/part2/part3          ../../../work/part1/part2/part3
/home/part1/part2      /work/part1/part2/part3/part4    ../../../work/part1/part2/part3/part4
home/part1/part2       home/part1/part3                 ../part3
home/part1/part2       home/part4/part5                 ../../part4/part5
home/part1/part2       work/part6/part7                 ../../../work/part6/part7
home/part1             work/part1/part2/part3/part4     ../../work/part1/part2/part3/part4
home                   work/part2/part3                 ../work/part2/part3
.                      work/part2/part3                 work/part2/part3
home/part1/part2       home/part1/part2/part3/part4     part3/part4
home/part1/part2       home/part1/part2/part3           part3
home/part1/part2       home/part1/part2                 .
home/part1/part2       home/part1                       ..
home/part1/part2       home                             ../..
home/part1/part2       .                                ../../..
home/part1/part2       work                             ../../../work
home/part1/part2       work/part1                       ../../../work/part1
home/part1/part2       work/part1/part2                 ../../../work/part1/part2
home/part1/part2       work/part1/part2/part3           ../../../work/part1/part2/part3
home/part1/part2       work/part1/part2/part3/part4     ../../../work/part1/part2/part3/part4
票数 1
EN

Stack Overflow用户

发布于 2015-02-18 08:54:42

作为一种快速的解决方案(忽略双斜杠、.././),您可以计算源代码中的斜杠数量,并在前面添加相同数量的../

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28574051

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档