(동일한 디렉토리에 있는) 다른 대상을 가리키도록 대상의 모든 심볼릭 링크를 바꾸는 스크립트

(동일한 디렉토리에 있는) 다른 대상을 가리키도록 대상의 모든 심볼릭 링크를 바꾸는 스크립트

다음과 같은 인위적인 예를 들어보세요.

$ mkdir -p a/b && touch a/b/original-target && touch a/b/new-target
$ mkdir -p c1/c2 && cd c1/c2 && ln -s ../../a/b/original-target && cd -
$ mkdir -p d1/d2/d3 && cd d1/d2/d3 && ln -s ../../../a/b/original-target && cd -
$ tree .
.
├── a
│   └── b
│       ├── new-target
│       └── original-target
├── c1
│   └── c2
│       └── original-target -> ../../a/b/original-target
└── d1
    └── d2
        └── d3
            └── original-target -> ../../../a/b/original-target

모든 심볼릭 링크 original-targetnew-target. 심볼릭 링크는 상대 경로를 사용해야 합니다.

답변1

globstar나는 당신이 bash 를 사용한다고 **가정 하고 있으므로 . 그 후에 남은 것은 조금 플레이하고 readlink기다리는 것 입니다 realpath.

shopt -s globstar
for file in c1/** d1/**; do
    if [[ -h "$file" ]]; then
        if [[ "$(readlink -f "$file")" == "$(realpath a/b/original-target)" ]]; then
            ln -sf "$(dirname "$(readlink "$file")")"/new-target "$(dirname "$file")" && rm -f "$file"
        fi
    fi
done

답변2

pax할 수 있다진짜이러한 상황에 유용합니다. 실제로 pax이 작업을 수행하는 옵션을 찾을 수 있다면 -o listopt=...더 쉬울 것입니다 .POSIX에 의해 지정됨그런데 아무리 둘러봐도 이렇게 할 수 있는 사람을 못 봤습니다. 나는 mirabilos - BSD에서 관리하는 것을 사용합니다.pax ( mirabipax?)- 내가 아는 한, 이것은 아마도 대부분의 다른 사람들이 하는 일일 것입니다. 어쨌든 정규식 파일 이름과 파일 목록을 얻을 수 있습니다. 예를 들어:

(set -e; mkdir -p a/b c1/c2 d1/d2/d3
touch a/b/original-target a/b/new-target
cd c1/c2; ln -s ../../a/b/original-target
cd ../../d1/d2/d3; ln -s ../../../a/b/original-target)

이것은 당신의 나무입니다. 이제 그것들을 나열하겠습니다:

pax -ws'|\(\..*/original-target.*\)*.*|\1|' ././ | 
pax -cvs'|\(.*\)/original|\1/new|p' \
     '././a/b/original-target' '*/original-target?*'

어떤 인쇄물이...

././d1/d2/d3/original-target >> ././d1/d2/d3/new-target
lrwxrwxrwx  1 mikeserv mikeserv         0 Dec  7 18:17 ././d1/d2/d3/new-target => ../../../a/b/new-target
././c1/c2/original-target >> ././c1/c2/new-target
lrwxrwxrwx  1 mikeserv mikeserv         0 Dec  7 18:14 ././c1/c2/new-target => ../../a/b/new-target

좋아요, 첫 번째 항목이 pax아카이브를 작성합니다. 제가 제공한 정규식 인수는 여기서 두 번째 항목과 마찬가지로 스트림에서 파일 이름을 변경하는 데 가장 일반적으로 사용되지만 한두 가지 트릭을 사용하여 필터링하는 데에도 사용할 수 있습니다. 아카이브에 추가된 파일.ustarstdout-spax

-s이 인수를 적용한 후 비어 있는 파일 이름은 아카이브에서 완전히 제거되도록 지정되어 있음 을 알 수 있습니다 . 그래서 정규 표현식을 사용하여 모든 파일 이름을 일치 시키고 \1. -w- 이는 쉘 전역 변수에 따라 다르므로 재귀적이지 않습니다.

그럼에도 불구하고 작성된 정규식은 모든 문자를 따르므로 다른 한편으로는 /original-target아카이브를 나열할 때 선택 항목에서 구현한 패턴 중 하나가 바로 거기에 배치된다는 것입니다. 비록 완벽하지는 않더라도 - 내 말은, 아마도 패턴을 두 번 포함하는 링크가 있을 수도 있지만... 음, 그게 바로 그 것이고 - 꽤 좋습니다. 추가 테스트를 통해 동일한 방식으로 처리할 수 있습니다. 어쨌든, 나는 그 자체에 대한 일치도 구현했기 때문에 목록 출력에서도 제거되었습니다.-c*/original-target?*-c././a/b/original-file

목록 모드에서 - ead 또는 rite 가 pax없을 때 수행되는 작업입니다 .-r-wpax장황하게-format-에는 - ls -l와 같은 모든 소프트 링크 대상이 포함되지만 link => target적용 가능한 매개변수를 적용한 후에만 가능합니다 -s. -s수정자가 다음 형식으로 적용될 때마다 -v정확히 동일한 매개변수가 인쇄됩니다 -s|...|...|p.p

"%s>>%s\n",원래 경로 이름,새 경로 이름

././따라서 위에서는 그렇지 않으면 표시되지 않는 목록과 목록을 분리합니다. 이제 일이 매우 간단해졌습니다. 여러분도 동의하시기를 바랍니다. 이러한 유형의 데이터를 적용하는 방법은 독자가 결정하도록 하겠습니다. ln매우 간단해야 하지만굳이 이렇게까지 할 필요도 없어.

실제로 해당 사양은 pax사용자, 그룹, 링크 데이터, 파일 이름, 파일 소스 등과 같은 항목을 변경하기 위해 cli 옵션을 사용하여 읽기 또는 쓰기 시 아카이브를 변경할 수 있도록 하는 것입니다. 이것들은 매우 강력한 파일 구문 분석 도구입니다. 그러나 제가 아는 구현에 가장 가까운 것은 GNU이며 부분적으로만 가능합니다. 헤더 유형에 영향을 줄 수 있는 방법을 찾지 못했습니다. 비록 어느 정도 그렇게 할 수는 있지만 cli 옵션을 사용하면 아카이브 자체에서 정규 표현식을 사용하는 것이 크게 어렵지는 않지만 말입니다. 이 항목에는 헤더 필드가 있습니다.rwpaxtar

... 2 - 심볼릭 링크를 나타냅니다. 심볼릭 링크의 내용은 다음 위치에 저장되어야 합니다.링크 이름대지.

제가 정말 하고 싶은 또 다른 pax일은 -o listopt=.... 다음은 사양의 예제 섹션에서 발췌한 내용입니다.

사용 옵션:

-o listopt="%M %(atime)T %(size)D %(name)s"

...표준 출력의 기본 출력 설명을 무시하고 대신 다음을 씁니다.

-rw-rw--- Jan 12 15:53 2003 1492 /usr/foo/bar

사용 옵션:

-o listopt='%L\t%(size)D\n%.7' \
-o listopt='(name)s\n%(atime)T\n%T'

...표준 출력의 기본 출력 설명을 무시하고 대신 다음을 씁니다.

/usr/foo/bar -> /tmp   1492
/usr/fo
Jan 12 15:53 1991
Jan 31 15:53 2003

그래서, 만약 당신이 그런 것을 우연히 발견한다면 pax...글쎄, 누가 보고 있는지 알 것입니다.

관련 정보