ディレクトリの深さに応じたシンボリックリンク

ディレクトリの深さに応じたシンボリックリンク

次のディレクトリ構造を作成し、同時にシンボリックリンクとして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

スクリプトでこれを行うにはどうすればよいですか?パスで/を数えて、私がそれからどれほど深いかを知る必要がありますか?よりスマートな方法がありますか?私はSolarisを使用しています。

答え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のコマンドは、ディレクトリの深さを理解し、どういうわけか問題を解決するのに役立ちます。

PS:私はSolarixについて知りませんが、Debianベースではtree次のコマンドがあります。

答え3

深呼吸をして、一度に1つの問題を解決し、簡単な解決策を見つけようとします。

まず、私たちがしなければならないことはすべてディレクトリの下で起こります/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を加えた値です。スラッシュ数を計算する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システムでは必要です-。)

関連情報