Symlink(ln)文件夹无法按预期工作

时间:2016-06-22 03:40:02

标签: bash symlink

我正在创建一个脚本,它基本上查找以.symlink结尾的所有内容,并尝试创建一个符号链接到$HOME目录,删除symlink部分并添加{{1在名字前面。

以下是显示目的地如何创建的行。

dot

为此创建了两个功能

dst="$HOME/.$(basename "${src%.*}")"

问题

我有一个名为create_symlink () { local src=$1 dst=$2 # Create the symlink ln -s -i "$src" "$dst" message "Linked $1 -------> $2" # This just use echo } run_symlinks() { message "Creating Symlinks" local root=$1 # Find the files/folder and try to do the symlink for src in $(find -H $root -name '*.symlink') do dst="$HOME/.$(basename "${src%.*}")" create_symlink "$src" "$dst" done } 文件夹,该文件夹基本上具有我的环境的一些配置,其中包含Atom文本编辑器的文件。当我运行atom.symlink功能时,该文件夹正在同步但位置错误。

run_symlinks的输出是:

message "Linked $1 -------> $2"

但是当我查看文件夹时,符号链接实际上是Linked $HOME/.dotfiles/src/symlinks/atom.symlink -------> $HOME/.atom 而不是$HOME/.atom/atom.symlink文件夹。

注意: .atom文件夹不为空,我需要弄清楚如何制作此脚本而不用担心有空文件夹。

我试图在Google上找到答案,但我甚至不知道如何询问有关它的具体问题。

2 个答案:

答案 0 :(得分:3)

来自man ln

   ln [OPTION]... [-T] TARGET LINK_NAME   (1st form)
   ln [OPTION]... TARGET                  (2nd form)
   ln [OPTION]... TARGET... DIRECTORY     (3rd form)
   ln [OPTION]... -t DIRECTORY TARGET...  (4th form)

   In  the 1st form, create a link to TARGET with the name LINK_NAME.  In the
   2nd form, create a link to TARGET in the current directory.   In  the  3rd
   and  4th  forms,  create  links  to each TARGET in DIRECTORY.  Create hard
   links by default, symbolic links with --symbolic.  By default, each destination
   (name  of  new link) should not already exist.  When creating hard
   links, each TARGET must exist.  Symbolic links can hold arbitrary text; if
   later  resolved,  a relative link is interpreted in relation to its parent
   directory.

首次迭代脚本后,您有

$HOME/.atom/ -> $HOME/.dotfiles/src/symlinks/atom.symlink # This is the first form in above man page snippet.

在第二次迭代中,你属于第三种形式,因为目标已存在&在符号链接解除引用之后,它就是一个目录。

因此,命令运行是相同的:

  ln -s -i $HOME/.dotfiles/src/symlinks/atom.symlink $HOME/atom

唯一不同的是,在第二次迭代中,目标是现有目录(在解除引用后)。

所以你应该先删除目标(rm -f "$dst")&然后创建一个符号链接。幸运的是,ln可以自行完成:

将您的代码更改为:

ln -sfn "$src" "$dst" # Note that with -f & -n in place, usage of -i is moot.

答案 1 :(得分:1)

补充anishsane's helpful answer,这可以很好地解释您的方法的问题:

希望在$HOME中保留可能已存在的(非符号链接)目标文件夹,并添加到其内容,这需要根本不同的方法< /强>:

解决此问题的唯一方法是避免自己对*.symlink 目录进行符号链接;相反,这些目录中的文件必须单独符号链接到目标文件夹,该文件夹是预先存在的文件夹或必须根据需要创建为常规文件夹的文件夹。登记/> 这是保证目标文件夹的现有内容不会(总是)丢失的唯一方法:

while IFS= read -r f; do
  # Strip $root from the file path, then remove suffix '.symlink' and add prefix '.'
  # to the path commponent(s) to get the link path.
  link="$HOME/$(sed 's#\([^/]\{1,\}\)\.symlink\(/\{0,1\}\)#.\1\2#g' <<<"${f#$root/}")"
  # Make sure that the parent path exists, creating it on demand (as *regular* folder(s)).
  mkdir -p -- "$(dirname -- "$link")"
  # Now we can create the symlink.
  echo "symlinking [$link] <- [$f]"
  # Note the need to redirect from `</dev/tty` so as not
  # to suppress the interactive prompt (`-i`).
  ln -s -i "$f" "$link" </dev/tty
done < <(find -H "$root" -type f \( -path '*.symlink' -or -path '*.symlink/*' \)) 

方法如下:

  • find命令只查找文件,即那些名为*.symlink自己,以及目录中的那些 em>命名为*.symlink(文件本身具有的后缀)。

  • 对于每个文件,通过删除$root路径前缀,然后删除后缀.symlink并将前缀.添加到匹配的路径组件来确定目标符号链接路径。< / p>

  • 使用mkdir -p确保每个目标符号链路路径的父路径的存在:任何现有路径组件按原样保留,任何不存在的路径组件都创建为常规文件夹。

  • 一旦确保/建立了符号链接的目标文件夹,就可以调用ln命令。

    • 请注意-i - 在链接的路径已经存在的情况下呈现要求替换的交互式提示 - 要求stdin成为终端才能启动;因此,鉴于stdin被重定向到提供find输出的进程替换,需要</dev/tty来显示提示。