我正在准备一个 bash 脚本来验证符号链接的正确性。我想诊断时间:
在诊断符号链接指向符号链接时,第2点我遇到了大问题。
我尝试使用 readlink ,但它返回符号链接的最终目标,而不是指向符号链接名称。我尝试在没有-f
参数的情况下运行它,但它没有帮助。然后与发现的组合给了我糟糕的结果......
任何人都可以帮我解决这个问题吗?
下面我将代码粘贴到当前版本中。
failed=0
for file in path/*
do
if [[ -L "$file" ]]
then
if [[ ! -a "$file" ]]
then
echo "Symlink '$file' is broken -- target object doesn't exists."
failed=1
elif [[ -L "$(readlink -f $file)" ]]
then
echo "Symlink '$file' points to another symlink: '$(readlink $file)'"
failed=1
fi
fi
done
exit $failed
更新
测试文件结构(其中 symlinks.sh 讨论了bash脚本):
答案 0 :(得分:1)
从您的问题描述中不清楚如何处理传递链末尾的断开链接。我只会报告一个错误并继续前进。
#!/bin/sh
rc=0
for file in path/*; do
if [ -L "$file" ]; then
nfile=$file
while [ -L "$nfile" ]; do
nfile=$(cd $(dirname "$nfile"); abspath $(readlink "$nfile"))
done
if ! [ -r "$nfile" ]; then
echo "$0: $file eventually resolves to nonexistent target $nfile" >&2
rc=1
else
# FIXME: maybe avoid doing this needlessly?
rm "$file"
ln -s "$nfile" "$file"
fi
fi
done
exit "$rc"
我是否正确理解您希望将符号链接(递归等)的符号链接替换为最终目标的符号链接?这个脚本可以做到这一点,虽然有些过分,但它会重写所有解析的符号链接;优化这一点,以避免不必要地做它是一个练习。
答案 1 :(得分:0)
我不是bash的专家,所以有人可能会向我们展示更简单的解决方案,但是这次我分享了我的脚本(它确保符号链接与相对链接的相对路径):
#!/bin/sh
# The task is to create bash script, which validates symlinks and reports when:
# (1) - symlink is broken
# (2) - symlink target point is broken
# (3) - symlink points to another symlink
# (4) - symlinks chain is a cycle
FAILED=0
FIX_SYMLINKS=false
DIR_UP="../"
function file_under_symlink_absolute_path {
local file_under_symlink="$(readlink $1)"
local file_dirname="$(dirname $1)"
if [[ "$file_under_symlink" == *"$DIR_UP"* ]]; then
if [[ "$file_under_symlink" == *"$DIR_UP$DIR_UP"* ]]; then
while [[ "$file_under_symlink" == *"$DIR_UP"* ]]; do
local file_under_symlink="${file_under_symlink#$DIR_UP}"
if [[ "$file_dirname" == *"/"* ]]; then
local file_dirname="${file_dirname%/*}"
else
local file_dirname=""
fi
done
if [[ "$file_dirname" != "" ]]; then
local file_dirname="$file_dirname/$file_under_symlink"
else
local file_dirname="$file_under_symlink"
fi
else
if [[ "$file_dirname" == *"/"* ]]; then
local file_dirname="${file_dirname%/*}/${file_under_symlink#$DIR_UP}"
else
local file_dirname="${file_under_symlink#$DIR_UP}"
fi
fi
else
local file_dirname="$file_dirname/$file_under_symlink"
fi
echo "$(pwd)/$file_dirname"
}
function file_under_symlink_relative_path {
local file_dirname="$(dirname $1)"
local symlink_target="$2"
local file_under_symlink="$3"
if [[ "$symlink_target" == *"$file_dirname"* ]]; then
local prefix2cut="$(pwd)/$file_dirname"
local target="${symlink_target##$prefix2cut}"
else
local symlink_target_dirname="$(dirname $symlink_target)"
local symlink_target_basename="$(basename $symlink_target)"
if [[ "$file_under_symlink" == "$symlink_target_dirname"* ]]; then
local level_diff="${file_under_symlink#$symlink_target_dirname/}"
local target="$symlink_target_basename"
while [[ "$level_diff" == *"/"* ]]; do
local level_diff="${level_diff%/*}"
local target="$DIR_UP$target"
done
else
if [[ "$file_dirname" == *"/"* ]]; then
local prefix2cut="$(pwd)/${file_dirname%/*}/"
else
local prefix2cut="$(pwd)/"
fi
local target="$DIR_UP${symlink_target#$prefix2cut}"
fi
fi
echo "$target"
}
function valid_symlinks {
local current_dir="$1"
for file in "$current_dir"/*; do
if [[ -d "$file" ]]; then
valid_symlinks "$file"
elif [[ -L "$file" ]]; then
local symlink_target=$(readlink -e "$file")
local file_under_symlink_abs="$(file_under_symlink_absolute_path $file)"
# reports (1), (2), (4)
if [[ ! -a "$file" ]]; then
echo "BROKEN Symlink '$file' is broken, target object doesn't exists."
FAILED=1
# reports (3)
# it happends when file under symlink is not the symlink target file
elif [[ "$file_under_symlink_abs" != "$symlink_target" ]]; then
if $FIX_SYMLINKS && [[ -r "$symlink_target" ]]; then
local target="$(file_under_symlink_relative_path $file $symlink_target $file_under_symlink_abs)"
echo "Symlink '$file' points to another symlink. It will be replace with direct symlink to target '$target'."
ln -fs "$target" "$file"
else
local target="${file_under_symlink_abs#$(pwd)/}"
echo "Symlink '$file' points to another symlink '$target'."
FAILED=1
fi
fi
fi
done
}
if [[ -d "$1" ]]; then
start_point=${1#$(pwd)/}
start_point=${start_point%/}
valid_symlinks "$start_point"
else
echo "ERROR: You have to specify the start location path."
FAILED=1
fi
exit $FAILED