根据目录深度的符号链接

根据目录深度的符号链接

我需要创建以下目录结构,同时,我还需要创建作为符号链接的 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

存档 1stdepth.zip、2nddepth.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

深呼吸,一次解决一个问题,力求简单的解决方案。

首先,我们需要做的一切都发生在目录下/a/2015-08-17。那么让我们切换到该目录。

cd /a/2015-08-17

现在我们需要根据现有目录创建一堆符号链接。 (我假设这些目录已经存在,因为您没有解释如何确定要创建哪些目录。)对当前目录的所有子目录执行某些操作的基本命令是

find . -type d …

我们需要做的是根据目录深度创建一个符号链接。符号链接的名称是目录的基本名称加上.zip末尾(除非它位于a.zip顶部),目标是根据深度计算的。让我们先做链接名称。

我们需要对 找到的每个目录进行一些计算find,因此我们需要调用 shell。

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
' {} \;

否则我们需要提取目录的基本名称。这可以通过 shell 参数扩展构造来完成${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。计算斜杠数量的一种方法是删除所有其他字符并计算剩余字符的长度。

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

使用zsh(Solaris 上的可选包),使用一些典型的只写语法:

$ 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

删除“回声”以实际执行此操作。

其中 zsh 特定功能的一些细分:

  • for f (...) cmd: 的缩写形式for i in ...; do ...; done。只是语法上的区别。
  • **/*:递归全局(其他一些 shell 也复制了它
  • (/): glob 限定符:此处仅选择类型的文件目录。对于其他 shell,您可以*/这样做,但也可以包含指向目录的符号链接。
  • ${(s:/:)i}: 变量扩展标志。在这里,s要分开/
  • ${#${...}}:zsh 扩展通常可以嵌套。这里${#array}返回数组中的元素数量,因此对于a/b/c, 3。
  • ${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 系统上则需要-)。

相关内容