我需要创建以下目录结构,同时,我还需要创建作为符号链接的 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
我想tree
Linux中的命令可以帮助您了解目录的深度并以某种方式解决您的问题。
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 系统上则需要-
)。