I would like to give an answer based on grg's answer Above you will learn how to convert all found broken symlinks into a reusable shell form, portable in Bash and ZSH.
I would also like to mention the following two equivalences, they will work the same:
find ... ! -exec test -e {} \;
That means if the pathname (which resolves symlinks) exists, it won't be found. “!” is used here by “find”. Can also replace “-not” instead of “!”find ... -exec test ! -e {} \;
That is, if the pathname (which resolves symlinks) doesn't exist, search for it. “!” is used here by “test”. I will use this in the example below.
Example for (1) saving, (2) printing and (3) counting the broken symlinks
pathnames=()
while IFS= read -r -d $'\0' pathname; do
pathnames+=( "$pathname" )
done < <(find . -type l -exec test ! -e {} \; -print0)
for (( i=0; i<${#pathnames[@]}; i++ )); do
printf "%q\n" "${pathnames[@]:"$i":1}"
done
printf "\nBroken symlinks found: %s\n" "${#pathnames[@]}"
pathnames
is an array for storing the pathnames found, in this case broken symlinks.find . -type l -exec test ! -e {} \;
means checking for broken symlinks in and under the current directory.-type l
finds symlinks andtest ! -e
tests whether the pathname resolved by the symlink does not exist.-print0
means to delimit the path names foundfind
with NUL bytes and print.< <(...)
means process substitution in Bash/Zsh.while ... read
means runningread
until the end of the file is reached or an error occurs.IFS=
means that spaces at the end/beginning of the pathname are not truncated.-r
means that backslashes cannot be used as escape characters; Do not interpret backslashes.-d $'\0'
or-d ''
means that an input delimited by NUL bytes is read.printf "%q\n"
uses the built-in functions of bash/zshprintf
to print out pathnames in a shell reusable form."${pathnames[@]:"$i":1}"
Uses 0-indexed array indexing, portable array indexing in Bash/ZSH.
Further information on the while ... read
Ribbon: https://mywiki.wooledge.org/BashFAQ/001
Example structure
Create some broken symlinks and broken directory symlinks with some newlines and carriage returns:
ln -s nofile 'broken symlink'
ln -s nofile $'broken symlink\nwith\nnewlines'
ln -s nofile $'broken symlink with\r carriage return'
mkdir tempdir
ln -s tempdir 'broken dir symlink'
ln -s tempdir $'broken \r dir \n_symlink'
sleep 1; rm -d tempdir
sleep 1
is used for Finder to catch up on displaying symlink folder icons for the two broken symlink directories.
Output to zsh and then to bash
./broken\ symlink
./broken\ symlink\ with$'\r'\ carriage\ return
./broken\ $'\r'\ dir\ $'\n'_symlink
./broken\ dir\ symlink
./broken\ symlink$'\n'with$'\n'newlines
Broken symlinks found: 5
./broken\ symlink
$'./broken symlink with\r carriage return'
$'./broken \r dir \n_symlink'
./broken\ dir\ symlink
$'./broken symlink\nwith\nnewlines'
Broken symlinks found: 5