批量重命名主文件夹中的符号链接?

批量重命名主文件夹中的符号链接?

在新的 SSD 上安装 Linux 时,我创建了一个newuser与旧系统名称不同的用户olduser。我成功地rsync将所有文件从旧系统移动到了新 SSD 的主分区。但特别是在.steam文件夹中,有大量符号链接(软链接)仍然使用/home/olduser,而不是~$HOME。我开始在 Bash 中重命名其中一些,但后来意识到它们太多了,比如 > 6000!

所以我的问题是:是否有一个 Bash/Python/Whatever 脚本可以

  1. 列出文件夹中的所有符号链接,包括子文件夹(ls -lR /path/to/folder | grep '^l'),以及
  2. 将所有/home/olduser符号/home/newuser链接重命名

答案1

/这可能有点棘手,因为从理论上讲,文件名可以包含除NUL 字节 ( )之外的任何内容\0。这使得解析 的输出变得ls->困难,因为您可以拥有一个名为 的文件file -> foo

$ touch 'file -> foo'
$ ls
'file -> foo'

另外,由于名称可以包含换行符,因此您建议的方法ls -l | grep '^l'无法帮助您轻松收集名称:

$ ln -s 'file -> foo' 'some name'$'\n''with a newline'
$ ls -l 
total 0
-rw-r--r-- 1 terdon terdon  0 Oct 15 12:36 'file -> foo'
lrwxrwxrwx 1 terdon terdon 11 Oct 15 12:37 'some name'$'\n''with a newline' -> 'file -> foo'
$ ls -l | grep '^l'
lrwxrwxrwx 1 terdon terdon 11 Oct 15 12:37 some name

如上所示,这只能捕获第一个换行符之前的文件名。所以我们需要更好的方法。幸运的是,find有一个选项可以仅查找符号链接:

$ find . -type l
./some name?with a newline

有了这个,我们可以获取所有符号链接的列表,读取它们的目标并将其更改为更新的用户名:

find . -type l -print0 | 
  while IFS= read -r -d '' linkName; do 
    target=$(readlink -- "$linkName")
    newTarget=$(sed 's|^/home/olduser/|/home/newuser/|' <<<"$target")
    if [[ "$newTarget" != "$target" ]]; then 
       rm -- "$linkName" && 
       ln -s -- "$newTarget" "$linkName"
    fi
  done

让我们详细分析一下:

  • find . -type l -print0:这会查找当前目录中的所有链接,并将它们打印为 NUL\0分隔列表。这让我们可以安全地处理奇怪的文件名,例如包含换行符的文件名。

  • while IFS= read -r -d '' linkName; do ...; done:我们将上一个命令的输出传递find给此 while 循环,该循环读取以空字符分隔的 iunput ( -d '') 并将IFS变量设置为空字符串以避免在空格处拆分。确保在文件名中找到的-r任何转义字符(例如\r\t)都不会被视为转义字符,而是被视为简单字符串,以便我们可以处理\名称中包含 的文件。循环本身会遍历 返回的每个链接名称find,并将其保存为$linkName

  • target=$(readlink "$linkName"):这是链接指向的目标。请注意,我不是这里使用是-f因为我们不想要最终目标,我们只想要第一级。这里其实没什么关系,因为如果目标目录不存在,你的所有链接都会被破坏,但这样更安全。

  • newTarget=$(sed 's|^/home/olduser/|/home/newuser/|' <<<"$target"):我们用sed替换/home/olduser/目标名称开头的 found ,/home/newuser/并将结果路径保存为$newTarget

  • if [[ "$newTarget" != "$target" ]]; then:如果新的目标名称与旧的目标名称不同。

  • rm -- "$linkName" && ln -s -- "$newTarget" "$linkName":删除现有链接,如果删除成功(&&),则创建一个具有相同名称但指向新目标的新符号链接。

这应该可以安全地用于任意文件名。

相关内容