다음과 같은 인위적인 예를 들어보세요.
$ 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-target
를 new-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
아카이브를 작성합니다. 제가 제공한 정규식 인수는 여기서 두 번째 항목과 마찬가지로 스트림에서 파일 이름을 변경하는 데 가장 일반적으로 사용되지만 한두 가지 트릭을 사용하여 필터링하는 데에도 사용할 수 있습니다. 아카이브에 추가된 파일.ustar
stdout
-s
pax
-s
이 인수를 적용한 후 비어 있는 파일 이름은 아카이브에서 완전히 제거되도록 지정되어 있음 을 알 수 있습니다 . 그래서 정규 표현식을 사용하여 모든 파일 이름을 일치 시키고 \1
. -w
- 이는 쉘 전역 변수에 따라 다르므로 재귀적이지 않습니다.
그럼에도 불구하고 작성된 정규식은 모든 문자를 따르므로 다른 한편으로는 /original-target
아카이브를 나열할 때 선택 항목에서 구현한 패턴 중 하나가 바로 거기에 배치된다는 것입니다. 비록 완벽하지는 않더라도 - 내 말은, 아마도 패턴을 두 번 포함하는 링크가 있을 수도 있지만... 음, 그게 바로 그 것이고 - 꽤 좋습니다. 추가 테스트를 통해 동일한 방식으로 처리할 수 있습니다. 어쨌든, 나는 그 자체에 대한 일치도 구현했기 때문에 목록 출력에서도 제거되었습니다.-c
*/original-target?*
-c
././a/b/original-file
목록 모드에서 - ead 또는 rite 가 pax
없을 때 수행되는 작업입니다 .-r
-w
pax
장황하게-format-에는 - ls -l
와 같은 모든 소프트 링크 대상이 포함되지만 link => target
적용 가능한 매개변수를 적용한 후에만 가능합니다 -s
. -s
수정자가 다음 형식으로 적용될 때마다 -v
정확히 동일한 매개변수가 인쇄됩니다 -s|...|...|p
.p
"%s>>%s\n",원래 경로 이름,새 경로 이름
././
따라서 위에서는 그렇지 않으면 표시되지 않는 목록과 목록을 분리합니다. 이제 일이 매우 간단해졌습니다. 여러분도 동의하시기를 바랍니다. 이러한 유형의 데이터를 적용하는 방법은 독자가 결정하도록 하겠습니다. ln
매우 간단해야 하지만굳이 이렇게까지 할 필요도 없어.
실제로 해당 사양은 pax
사용자, 그룹, 링크 데이터, 파일 이름, 파일 소스 등과 같은 항목을 변경하기 위해 cli 옵션을 사용하여 읽기 또는 쓰기 시 아카이브를 변경할 수 있도록 하는 것입니다. 이것들은 매우 강력한 파일 구문 분석 도구입니다. 그러나 제가 아는 구현에 가장 가까운 것은 GNU이며 부분적으로만 가능합니다. 헤더 유형에 영향을 줄 수 있는 방법을 찾지 못했습니다. 비록 어느 정도 그렇게 할 수는 있지만 cli 옵션을 사용하면 아카이브 자체에서 정규 표현식을 사용하는 것이 크게 어렵지는 않지만 말입니다. 이 항목에는 헤더 필드가 있습니다.r
w
pax
tar
... 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
...글쎄, 누가 보고 있는지 알 것입니다.