我有一个文件列表,我需要知道其中哪些文件位于符号链接后面。例如。
var/storage/media/foo.jpg
var/storage/documents/bar.doc
var/logs/baz.log
如果只是var/storage
一个符号链接,那么我想要获取列表:
var/storage/media/foo.jpg
var/storage/documents/bar.doc
原始列表中的每个文件可能存在也可能不存在
(例如,即使symlinked/documents
文件夹丢失,我仍然希望bar.doc
出现在结果中。
我如何在 bash 中实现这一点?
如果可能的话,一行代码是最好的。
答案1
找到一种方法将给定路径转换为其父级列表。(在 Bash 中,通过剥离最后一个组件会更容易,在其他语言中,将路径拆分为组件并在循环中重新连接它们可能会更容易 - 假设它是没有驱动器号或其他花哨语法的 Unix 样式路径)。
然后,对于结果列表中的每个项目,执行常规检查以确定它是否是符号链接(例如,在 sh/bash 中[ -h the_path ]
对每个父母/祖父母/等执行此操作)。
一句话:
cat files.txt | perl -MList::Util=reductions -n -E 'chomp; say if grep {-l} reductions {"$a/$b"} split "/"'
不是一行代码(尽管你可以把所有内容都写在一行中非常如果需要的话可以排长队):
is_behind_symlink() {
local path=$1
while [ "$path" ]; do
if [ -L "$path" ]; then
return 0
fi
case $path in
*/*) path=${path%/*} ;;
*) break ;;
esac
done
return 1
}
while read -r path; do
if is_behind_symlink "$path"; then
echo "$path"
fi
done < files.txt
您也可以这样做,但是每个文件会生成两个子进程,因此速度不快:
is_behind_symlink() {
local path=$1
[[ "$(realpath -s "$path")" != "$(realpath -m "$path")" ]]
}
这是每个路径一个过程(仍然不是很好)并且依赖于解析namei -l
(这样做不是好风格):
is_behind_symlink() {
local path=$1
namei -l -n "$path" | grep -q ^l
}