디렉토리 깊이에 따른 심볼릭 링크

디렉토리 깊이에 따른 심볼릭 링크

다음 디렉터리 구조를 생성해야 하며 동시에 심볼릭 링크로 zip 파일도 생성해야 합니다.

/a/2015-08-17/a.zip  
/a/2015-08-17/a_b/a_b.zip
/a/2015-08-17/a_b/a_b_c/a_b_c.zip
/a/2015-08-17/a_b/a_b_c/a_b_c_1/a_b_c_1.zip 
/a/2015-08-17/a_b/a_b_c/a_b_c_2/a_b_c_2.zip
/a/2015-08-17/a_b/a_b_c/a_b_c_3/a_b_c_3.zip

1st뎁스.zip, 2nd깊이.zip 등의 아카이브가 모두 존재하며 매번 동일합니다. 위와 비슷한 디렉터리 구조가 있으며 디렉터리 구조의 깊이에 따라 다음 기호 링크를 만들어야 합니다.

ln -s 1stdepth.zip /a/2015-08-17/a.zip  
ln -s 2nddepth.zip /a/2015-08-17/a_b/a_b.zip
ln -s 3rddepth.zip /a/2015-08-17/a_b/a_b_c/a_b_c.zip
ln -s 4thdepth.zip /a/2015-08-17/a_b/a_b_c/a_b_c_1/a_b_c_1.zip  
ln -s 4thdepth.zip /a/2015-08-17/a_b/a_b_c/a_b_c_2/a_b_c_2.zip
ln -s 4thdepth.zip /a/2015-08-17/a_b/a_b_c/a_b_c_3/a_b_c_3.zip

스크립트에서 이 작업을 어떻게 수행합니까? 경로에서 /를 세어보고 내가 그로부터 얼마나 깊은지 알아야 합니까? 더 똑똑한 방법이 있나요? 저는 솔라리스를 사용하고 있습니다.

답변1

이것이 내가 문제를 해결한 방법입니다. 이것이 최선의 접근 방식은 아닐 수도 있지만 빠른 해결 방법이 필요합니다. 어쩌면 다른 사람이 필요할 수도 있습니다

#!/usr/bin/bash

function main()
{
[ $# -ne 1 ] && { echo "Usage: $0 file"; exit 1; }
depth1=/a.zip
depth2=/b.zip
depth2_special=/special.zip
depth3=/c.zip
depth4=/d.zip

cat $1 | while read line; do
#Count the number of occurences of / in each line 
x=`echo $line |awk -F/ '{c += NF - 1} END {print c}'`
if [ $x -eq 13 ] ;then echo "The path has 13 / " 
    ln -sf $depth4 $line 
else
    if [ $x -eq 12 ] ;then echo "The path has 12 /"
        ln -sf $depth3 $line 
    else
        if [ $x -eq 11 ] ; then echo "The path has 11 /"
            #If there is no _ in the file path treat it as a special case
            underscore=`echo $line |awk -F_ '{c += NF - 1} END {print c}'`
                if [ $underscore -eq 1 ] ; then
                    ln -sf $depth2 $line
                else
                    ln -sf $depth2_special $line 
                fi; 
        else
            if [ $x -eq 10 ] ;then echo "The path has 10 /" 
                ln -sf $depth1 $line 
            else
                echo "Error - the path is not correct" 
            fi;
        fi;
    fi; 
fi;
done

}

main "$@"

답변2

treeLinux의 명령은 디렉토리 깊이를 이해하고 어떻게든 문제를 해결하는 데 도움이 될 수 있다고 생각합니다 .

추신: 저는 Solarix에 대해 모르지만 데비안 기반에서는 tree다음 명령이 있습니다.

답변3

심호흡을 하고, 한 번에 하나의 문제를 해결하고, 간단한 해결책을 찾으려고 노력하십시오.

먼저, 우리가 해야 할 모든 일은 디렉토리 아래에서 발생합니다 /a/2015-08-17. 그럼 해당 디렉터리로 전환해 보겠습니다.

cd /a/2015-08-17

이제 기존 디렉터리를 기반으로 여러 기호 링크를 만들어야 합니다. (어떤 디렉토리를 생성할지 결정하는 방법을 설명하지 않았기 때문에 이러한 디렉토리는 이미 존재한다고 가정합니다.) 현재 디렉토리의 모든 하위 디렉토리에 대해 작업을 수행하는 기본 명령은 다음과 같습니다.

find . -type d …

우리가 해야 할 일은 디렉터리 깊이를 기반으로 심볼릭 링크를 만드는 것입니다. 심볼릭 링크의 이름은 디렉터리의 기본 이름에 .zip끝(맨 위에 있지 않은 경우 a.zip)을 더한 것이며 대상은 깊이를 기준으로 계산됩니다. 먼저 링크 이름을 지정해 보겠습니다.

발견된 각 디렉터리에 대해 몇 가지 계산을 수행해야 하므로 find셸을 호출해야 합니다.

find . -type d -exec sh -c '???' {} \;

디렉토리 경로( 로 시작 .)는 스크립트에서 로 사용할 수 있습니다 $0. $0그것이 정의라면 우리 .는 창조해야 합니다 a.zip.

find . -type d -exec sh -c '
    if [ "$0" = "." ]; then ln -s 1stdepth.zip a.zip; fi
' {} \;

그렇지 않으면 디렉터리의 기본 이름을 추출해야 합니다. 이는 쉘 매개변수 확장 구성 ${0##*/}(값 $0에서 a로 끝나는 가장 긴 접두어를 뺀 값 /)을 통해 수행할 수 있습니다.

find . -type d -exec sh -c '
    if [ "$0" = "." ]; then
      ln -s 1stdepth.zip a.zip
    else
      ln -s ???depth.zip "$0/${0##*/}.zip"
    fi
' {} \;

이제 깊이를 계산해야 합니다. 이는 $0루트의 깊이가 1이므로 중간 슬래시 수에 1을 더한 값입니다 . 슬래시 수를 계산하는 한 가지 방법은 다른 모든 문자를 제거하고 나머지 문자의 길이를 계산하는 것입니다.

find . -type d -exec sh -c '
    depth=$(printf %s "$0" | tr -dc / | wc -c)
    if [ "$0" = "." ]; then
      ln -s 1stdepth.zip a.zip
    else
      ln -s $((depth+1))???depth.zip "$0/${0##*/}.zip"
    fi
' {} \;

거의 다 되었습니다. 1위, 2위 등을 얻으려면 접미사를 세어야 합니다.

find . -type d -exec sh -c '
    depth=$(($(printf %s "$0" | tr -dc / | wc -c) + 1))
    if [ "$0" = "." ]; then
      ln -s 1stdepth.zip a.zip
    else
      case $depth in
        *1?) suffix=th;;
        *1) suffix=st;;
        *2) suffix=nd;;
        *3) suffix=rd;;
        *) suffix=th;;
      esac
      ln -s "${depth}${suffix}depth.zip" "$0/${0##*/}.zip"
    fi
' {} \;

답변4

(Solaris의 선택적 패키지)를 사용하면 zsh몇 가지 일반적인 쓰기 전용 구문을 사용합니다.

$ for i (*/**/*(/)) echo ln -s -- $((${#${(s:/:)i}}-1))??depth.zip $i/${${i%/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]}:t}.zip
ln -s -- 1stdepth.zip a/2015-08-17/a.zip
ln -s -- 2nddepth.zip a/2015-08-17/a_b/a_b.zip
ln -s -- 3rddepth.zip a/2015-08-17/a_b/a_b_c/a_b_c.zip
ln -s -- 4thdepth.zip a/2015-08-17/a_b/a_b_c/a_b_c_1/a_b_c_1.zip
ln -s -- 4thdepth.zip a/2015-08-17/a_b/a_b_c/a_b_c_2/a_b_c_2.zip
ln -s -- 4thdepth.zip a/2015-08-17/a_b/a_b_c/a_b_c_3/a_b_c_3.zip

실제로 이 작업을 수행하려면 "echo"를 제거하십시오.

zsh 특정 기능에 대한 일부 분석:

  • for f (...) cmd: 약어형 for i in ...; do ...; done. 단지 문법적인 차이일 뿐입니다.
  • **/*: 재귀 전역(다른 쉘도 복사했습니다.)
  • (/): glob 한정자: 여기에서 선택한 유형의 파일만목차. 다른 쉘의 경우 */이를 수행할 수 있지만 디렉토리에 대한 기호 링크를 포함할 수도 있습니다.
  • ${(s:/:)i}: 가변 확장 플래그입니다. 여기서는 s별도의 /.
  • ${#${...}}:zsh 확장자는 종종 중첩될 수 있습니다. 이는 ${#array}배열의 요소 수를 반환하므로 의 경우 a/b/c3입니다.
  • ${var:t}: csh와 마찬가지로 반환합니다.꼬리(기본 이름).

이제 이것은 귀하가 요청한 것이지만 실제로는 원하는 것이 아닐 수도 있습니다. 이로 인해 깨진 심볼릭 링크가 생성됩니다. 당신은 원할 수도 있습니다

ln -s -- /path/to/1stdepth.zip a/2015-08-17/a.zip

이 문제는 다음을 추가하여 쉽게 해결할 수 있습니다 $PWD.

for i (*/**/*(/)) echo ln -s -- $PWD/$((${#${(s:/:)i}}-1))??depth.zip $i/${${i%/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]}:t}.zip

아니면 상대 링크가 더 좋을 수도 있습니다.

ln -s ../../1stdepth.zip a/2015-08-17/a.zip

다음을 수행할 수 있습니다.

setopt extendedglob
for i (*/**/*(/)) {
  z=($((${#${(s:/:)i}}-1))??depth.zip)
  echo ln -s -- ${i//[^\/]##/..}/$z $i/${${i%/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]}:t}.zip
}

${i//[^\/]##/..}슬래시가 아닌 문자 시퀀스를 ...

( --Solaris에서는 필요하지 않지만 이름이 로 시작하는 디렉토리가 있는 경우 GNU 시스템에서는 필요합니다 -.)

관련 정보