生成多个符号链接,同时保持目录结构

生成多个符号链接,同时保持目录结构

我想从多个文件夹生成符号链接,同时维护目录结构。我读了一些答案,现在我能想到的最好的办法是:

find /data/DIV5/SASC/e042_ctcl/input/*/Clean_data/*/*/*.fq.gz -type f -exec ln -sf \{\} . \;

这会在同一目录中生成所有符号链接。但我想要的是具有与find命令中相同的目录结构,并且如果可能的话使用与输入相同的结构。例如:input/*/Clean_data/*/*/*.fq.gz

当文件和目录匹配时,符号链接应遵循与使用命令找到的绝对链接相同的结构find

任何意见都会受到赞赏。

答案1

丑陋且脆弱,但它应该可以完成工作:

find /data/DIV5/SASC/e042_ctcl/input/*/Clean_data/*/*/*.fq.gz -type f -print0 | \
  xargs -0 -n 1 \
    sh -c 'mkdir -p "$PWD/`dirname $0`"; ln -s "$0" "$PWD/`dirname $0`"'

灵感来自混沌的回答,我想出了这个替代方案,它也修剪不需要的目录:

find /data/DIV5/SASC/e042_ctcl/input/*/Clean_data/*/*/*.fq.gz -type f   \
     -printf 'mkdir -p "${PWD}/%h"; ln -s "%p" \\\n\t"${PWD}/%h"\n'   | \
sed 's#/data/DIV5/SASC/e042_ctcl##'                                   | \
sh -

它生成所需的目录命令:

mkdir -p "${PWD}//data/DIV5/SASC/e042_ctcl/input/x/Clean_data/0/a"; ln -s "/data/DIV5/SASC/e042_ctcl/input/x/Clean_data/0/a/foobar.fq.gz" \
    "${PWD}//data/DIV5/SASC/e042_ctcl/input/x/Clean_data/0/a"

然后它从其中删除不需要的目录sed, 导致:

mkdir -p "${PWD}//input/x/Clean_data/0/a"; ln -s "/data/DIV5/SASC/e042_ctcl/input/x/Clean_data/0/a/foobar.fq.gz" \
    "${PWD}//input/x/Clean_data/0/a"

命令在同一行开始目录并继续下一行,以便在修剪目标的同时保持源完整。将它们打印在同一行或将它们打印在自己不同的行上将需要更复杂的sed脚本。

解释来自文档为了寻找,参数-printf

%p 文件名(不是绝对路径名,而是 find 遇到的文件名 - 即,作为从起点之一开始的相对路径)。

%h 文件名的前导目录(除了最后一个元素及其前面的斜杠之外的所有目录)。如果文件名不包含斜杠(例如,因为它是在命令行上命名的并且位于当前工作目录中),则“%h”将扩展为“.”。这可以防止“%h/%f”扩展为“/foo”,这将是令人惊讶的并且可能是不可取的。

答案2

我应该生成命令,awk然后将它们通过管道传输到bash

find /data/DIV5/SASC/e042_ctcl/input/*/Clean_data/*/*/*.fq.gz -type f | \
awk '{printf "mkdir -p `dirname %s`\nln -s %s ./%s \n", substr($0, 27), $0, substr($0, 27)}'

这会生成一个命令列表,我首先控制它们,然后最后将其通过管道传输到bash.完整的命令是:

find /data/DIV5/SASC/e042_ctcl/input/*/Clean_data/*/*/*.fq.gz -type f | \
awk '{printf "mkdir -p `dirname %s`\nln -s %s ./%s \n", substr($0, 27), $0, substr($0, 27)}' | bash

答案3

我的印象是您正在寻找像这样的工具GNU 斯托

GNU Stow 是一个符号链接场管理器,它采用位于文件系统上不同目录中的不同软件和/或数据包,并使它们看起来安装在同一位置。例如,/usr/local/bin可以包含指向 等中的文件的符号链接/usr/local/stow/emacs/bin/usr/local/stow/perl/bin并且同样递归地包含任何其他子目录,例如.../share.../man等。

检查一下是否符合用例。

答案4

zsh有一个方便的功能zmv。首先,加载它(您可以从.zshrc或在命令行上执行此操作以进行单会话使用):

autoload -U zmv
alias zcp='zmv -C'
alias zln='zmv -L'

重新创建符号链接森林就像这样简单:

 zln -s '/data/DIV5/SASC/e042_ctcl/(input/*/Clean_data/*/*/*.fq.gz)' '$1'

如果您想Clean_data递归地遍历目录而不是只深入两层:

 zln -s '/data/DIV5/SASC/e042_ctcl/(input/*/Clean_data/**/*.fq.gz)' '$1'

有一个很大的限制:这不会创建必要的子目录。您可以通过定义和使用包装函数来根据ln需要创建目录来做到这一点。

ln_s_mkdir () {
  mkdir -p -- ${(P)#}
  ln -s "$@"
}
 zmv -p ln_s_mkdir '/data/DIV5/SASC/e042_ctcl/(input/*/Clean_data/**/*.fq.gz)' '$1'

您可以使用 zsh 使命令运行得更快一些内部mkdirln命令(默认情况下不会加载它们,因为它们在大多数系统上找到的 GNU 实用程序的选项较少)。

zmodload -F zsh/files b:zf_ln b:zf_mkdir
ln_s_mkdir () {
  zf_mkdir -p -- ${(P)#}
  zf_ln -s "$@"
}
 zmv -p ln_s_mkdir '/data/DIV5/SASC/e042_ctcl/(input/*/Clean_data/**/*.fq.gz)' '$1'

相关内容