Symbolic link source item can't be found - macos

I'm trying to make an alias of a directory in a set of directories
for D in $(find * -maxdepth 0 -type d) ; do
ln -s location/to/directory/ $D/Test2 ;
done
It looks like the link is made correctly (I can see it in my finder window), but when I double click it, I get the error The operation can't be completed because the original item for "Test2" can't be found.
Why doesn't this work? Is there a way from a bash script to make a "normal" mac alias? I have opened up the permissions, as suggested here, without any luck.

Use the absolute source path while creating the link. That worked for me having the same issue.

You want to create a symbolic link called Test2 in each directory in the current directory, and each created link should point to location/to/directory.
for dir in */; do
ln -s 'location/to/directory' "$dir/Test2"
done
The slash after * ensures that we will only match directories in the current directory, or links to directories in the current directory.
If you're only interested in real directories an not symbolically linked directories, you may use
find . -type d -mindepth 1 -maxdepth 1 \
-exec ln -s 'location/to/directory' {}/Test2 ';'
Note that the link destination is relative to the location of the link, so if a directory does not contain location/to/directory, the link will be "dead".
You may solve this be specifying an absolute path for the links.

What are you attempting to do?
Think of a link as a cp command. Maybe that will help:
# Copies the 'svnadmin' command from /opt/svn/bin to /usr/local/bin
$ cp /opt/svn/bin/svnadmin /usr/local/bin
# Links the 'svnadmin' command from /opt/svn/bin to /usr/local/bin
$ ln -s /opt/svn/bin/svnadmin /usr/local/bin
Note that the ln and cp command have the same order of files.
In your command, you're linking whatever location/to/directory/ to $D/test2 over and over again.
Also, -maxdepth 0 won't be in the first level of the directory.
I use ln when I install new software, and the binary commands are in some other directory. Instead of building on $PATH to include all of these extra directories, I symbolically link them to /usr/local/bin:
$ cd /usr/share/apache-ant/bin
$ for file in *
> do
> [[ -f $file ]] || continue
> ln -s $PWD/$file /usr/local/bin/$file
> done
Note that the link simply copies the entire reference for the first file to the link. I want to make sure that this link works everywhere, so I prefix that $PWD in front of it. This way, my links look like this:
$ ls -l ant
lrwxr-xr-x 1 root wheel 29 Sep 3 2014 ant -> /usr/share/apache-ant/bin/ant

Related

zsh fzf search path is strange on Mac

I installed fzf for the zsh on my Mac
I usecd ** <Tab> , instead of getting a list of directories which can get into
I always get a long list of directories,such as
How to solve this problem?
when I search specific file, it always return a list of library container files of Mac file system, how to ignore them and just leave the real one.
it takes a very long time to get the top1 real result
BTW the first line numbers seems going infinite, why is that.
fzf default command search every files in your home diretory and follow every symbol links e.g. ~/Library/Container/*/Downloads which return files multi times.
According to the readme of fzf, you can specify FZF_DEFAULT_COMMAND and _fzf_compgen_path() _fzf_compgen_dir() to exclude directories what you don't want to see.
# Use fd (https://github.com/sharkdp/fd) instead of the default find
# remove -L of fzf default command
# export FZF_DEFAULT_COMMAND="find . -mindepth 1 -path '*/\.*\' -prune -o -type f -print -o -type l -print 2> /dev/null | cut -b3-"
export FZF_DEFAULT_COMMAND='fd --type f'
_fzf_compgen_path() {
fd --hidden --follow --exclude ".git" . "$1"
}
# Use fd to generate the list for directory completion
_fzf_compgen_dir() {
fd --type d --hidden --follow --exclude ".git" . "$1"
}
Just adding to the answer above:
install fd on your Mac via brew install fd
add the above mentioned code with FZF_DEFAULT_COMMAND to your .fzf.zsh (which you then need to load from your .zshrc via [ -f ~/.fzf.zsh ] && source ~/.fzf.zsh)
edit .fdignore file in your home dir to include dirs that you don't want to be included

Which module do I need when I got error info "Can't locate getopts.pl in #INC..."

I run this command in my macOS
$ perl ~/Desktop/blif2cnf.pl
and got this error info:
Can't locate getopts.pl in #INC (#INC contains: /Library/Perl/5.18/darwin-thread-multi-2level /Library/Perl/5.18 /Network/Library/Perl/5.18/darwin-thread-multi-2level /Network/Library/Perl/5.18 /Library/Perl/Updates/5.18.2 /System/Library/Perl/5.18/darwin-thread-multi-2level /System/Library/Perl/5.18 /System/Library/Perl/Extras/5.18/darwin-thread-multi-2level /System/Library/Perl/Extras/5.18 .) at /Users/Frank/Desktop/blif2cnf.pl line 10.
In my linux 16.04, such problem can be solved by following this answer
Is there a module like libperl4-corelibs-perl in macOS?
I know CPAN, but I don't know which module should I install.
It's Perl4::CoreLibs. In general the Debian package libthis-that-perl corresponds to a module named This::That, although it's up to you to figure out the capitalization :)
I'm not sure how the package manager works with macOS, but a platform-independent way of installing the getopts package.
To answer the question you put as a comment to the answer from #hobbs, the way I searche for a module I need is either through the site that #hobbs linked, https://metacpan.org, or, alternatively, http://search.cpan.org. It was at the second that I found what I needed.
Searching for getopts.pl gave a link to "Perl4::CoreLibs". In the upper-right-hand corner, there was a link that said Perl4-CoreLibs-0.003.tar.gz (though it looks like there is a 0.004 now). I right-clicked and selected "copy link address", which gave me
http://search.cpan.org/CPAN/authors/id/Z/ZE/ZEFRAM/Perl4-CoreLibs-0.004.tar.gz
Whatever your link is, you'll need to untar it and find all the *.pl files in the lib directory into a directory, and either
1) Link to them from the command line, e.g.
perl -I /path/to/where/you/untarred/lib ~/Desktop/blif2cnf.pl
or
2) Add them to your PERLLIB environment variable.
I think that more details will be helpful.
Detailed Instructions
Figure out a directory where you want to download your *.pl files. I used $HOME/new_perl_stuff
cd ~
mkdir new_perl_stuff
cd new_perl_stuff
Now, get the tarball
wget http://search.cpan.org/CPAN/authors/id/Z/ZE/ZEFRAM/Perl4-CoreLibs-0.004.tar.gz
untar it, go into the directory, and make sure lib is there
$ tar -xzf Perl4-CoreLibs-0.004.tar.gz
$ cd Perl4-CoreLibs-0.004
$ ls
You should see lib in the list.
It's possible to add your newly downloaded lib directory (in my case, $HOME/new_perl_stuff/Perl4-CoreLibs-0.004/lib) to the perl search path, but this just makes me worry about another directory that I might delete at some time. I made a new folder in the /usr/lib directory. I decided to name the new directory libperl4-corelibs-perl, since that seemed standard. First, I checked to make sure that there wasn't already a directory with that name.
$ stat /usr/lib/libperl4-corelibs-perl
stat: cannot stat '/usr/lib/libperl4-corelibs-perl': No such file or directory
Then I made the directory.
mkdir /usr/lib/libperl4-corelibs-perl
The next step was copying all the *.pl files into this directory. I hope to explain this next command later. I ran it this way to make sure all of the files I needed were there. From my $HOME/new_perl_stuff/Perl4-CoreLibs-0.004 directory, I ran the following command, which I plan to come back and explain.
find ./lib -type f -name "*.pl" -print0 | xargs -I'{}' -0 \
bash -c 'new_dir=/usr/lib/libperl4-corelibs-perl/; chmod +x {}; \
echo "Moving {}"; mv {} ${new_dir} && echo -e "success\n" || \
echo -e "failure\n"' | tee moving_day.log
Run that one if you want to see that everything got copied successfully. A shorter command that does everything necessary is:
find ./lib -type f -name "*.pl" -print0 | xargs -I'{}' -0 \
bash -c 'new_dir=/usr/lib/libperl4-corelibs-perl/; chmod +x {}; \
mv {} ${new_dir}'
It's not a bad idea to run
ls -lah /usr/lib/libperl4-corelibs-perl
to check that the *.pl files are there.
You can now run
perl -I /usr/lib/libperl4-corelibs-perl ~/Desktop/blif2cnf.pl
but there's an easier way.
Finally, I made it so that this directory will become part of the perl search path every time I use a terminal by adding the following line to my ~/.bashrc
This command adds the path to the PERLLIB environment variable. Different flavors of Linux have different syntax for adding to environment variables, make sure to find out what yours is!
export PERLLIB="/usr/bin/libperl4-corelibs-perl:$PERLLIB"
The commands I ran for this were
$ echo -e "\n\n## allow Perl to use the files in Perl4::CoreLibs" >> $HOME/.bashrc
$ echo -e "export PERLLIB=\"/usr/lib/libperl4_corelibs_perl:$PERLLIB\"" >> $HOME/.bashrc
$ source .bashrc
Now, you can simply run
perl ~/Desktop/blif2cnf.pl
Note: It's probably a good idea to go back and remove unwanted extras:
rm -rf $HOME/new_perl_stuff

Why is my link broken? Bash

I am trying to link files in a while loop for my script but just the simple linking code itself creates a broken link.
The directory structure is this:
main/working/script.sh
main/working/dir
main/shared/default/some_files
My script has this code:
ln -s ../shared/default/* dir
This creates broken link. I can make the link not broken if I go inside the directory of main/working/dir and use ln -s ../../shared/default/* .
That is because you link to a relative path; Inside your script go to main/working/:
cd main/working/
ln -s ../shared/default/* dir
either use the absolute path:
ln -s /absolute/path/to/shared/default/* dir
you might even deduce the path where your script is located and use that path:
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
ln -s $DIR/../../shared/default/* dir
edit: bash cannot expand the * if you are not at the right directory, so you can work around that to temporarily change directories:
# go to dir to make correct relative links
cd dir
ln -s $DIR/../../shared/default/* ./
cd ..

script for creating links

I have a folder (say /data) with a set of files say: a.txt, b.bin, c.bak, d.txt, e.bin. I need to create links to those files with the exact same name (1-1 mapping) in a folder (/dataIL). That is, /dataIL should have 5 links:
a.txt->../data/a.txt
b.bin->../data/b.bin
c.bak->../data/c.bak
d.txt->../data/d.txt
e.bin->../data/e.bin
The command to create one link is:
ln -s ../data/a.txt a.txt
Wondering what script commands I can run to create for all files. Note there files with other extensions too. I just need links to all files with any extension.
I have a bash shell. Thanks.
You can simply use the asterisk to create symbolic links to all the files since they're in one directory:
ln -s data/* .
This assumes you would like to create links to all the files in data. Note also that depending on your settings this may skip files with names starting with a dot.
find ../data -maxdepth 1 -type f -exec bash -c "ln -s {} \`basename {}\`" \;
../data can be any directory

How do I find all of the symlinks in a directory tree?

I'm trying to find all of the symlinks within a directory tree for my website. I know that I can use find to do this but I can't figure out how to recursively check the directories.
I've tried this command:
find /var/www/ -type l
… and later I discovered that the contents in /var/www are symlinks, so I've changed the command to:
find -L /var/www/ -type l
it take a while to run, however I'm getting no matches.
How do I get this to check subdirectories?
This will recursively traverse the /path/to/folder directory and list only the symbolic links:
ls -lR /path/to/folder | grep ^l
If your intention is to follow the symbolic links too, you should use your find command but you should include the -L option; in fact the find man page says:
-L Follow symbolic links. When find examines or prints information
about files, the information used shall be taken from the prop‐
erties of the file to which the link points, not from the link
itself (unless it is a broken symbolic link or find is unable to
examine the file to which the link points). Use of this option
implies -noleaf. If you later use the -P option, -noleaf will
still be in effect. If -L is in effect and find discovers a
symbolic link to a subdirectory during its search, the subdirec‐
tory pointed to by the symbolic link will be searched.
When the -L option is in effect, the -type predicate will always
match against the type of the file that a symbolic link points
to rather than the link itself (unless the symbolic link is bro‐
ken). Using -L causes the -lname and -ilname predicates always
to return false.
Then try this:
find -L /var/www/ -type l
This will probably work: I found in the find man page this diamond: if you are using the -type option you have to change it to the -xtype option:
l symbolic link; this is never true if the -L option or the
-follow option is in effect, unless the symbolic link is
broken. If you want to search for symbolic links when -L
is in effect, use -xtype.
Then:
find -L /var/www/ -xtype l
One command, no pipes
find . -type l -ls
Explanation: find from the current directory . onwards all references of -type link and list -ls those in detail.
Plain and simple...
Expanding upon this answer, here are a couple more symbolic link related find commands:
Find symbolic links to a specific target
find . -lname link_target
Note that link_target is a pattern that may contain wildcard characters.
Find broken symbolic links
find -L . -type l -ls
The -L option instructs find to follow symbolic links, unless when broken.
Find & replace broken symbolic links
find -L . -type l -delete -exec ln -s new_target {} \;
More find examples
More find examples can be found here: https://hamwaves.com/find/
find already looks recursively by default:
[15:21:53 ~]$ mkdir foo
[15:22:28 ~]$ cd foo
[15:22:31 ~/foo]$ mkdir bar
[15:22:35 ~/foo]$ cd bar
[15:22:36 ~/foo/bar]$ ln -s ../foo abc
[15:22:40 ~/foo/bar]$ cd ..
[15:22:47 ~/foo]$ ln -s foo abc
[15:22:52 ~/foo]$ find ./ -type l
.//abc
.//bar/abc
[15:22:57 ~/foo]$
To see just the symlinks themselves, you can use
find -L /path/to/dir/ -xtype l
while if you want to see also which files they target, just append an ls
find -L /path/to/dir/ -xtype l -exec ls -al {} \;
This is the best thing I've found so far - shows you the symlinks in the current directory, recursively, but without following them, displayed with full paths and other information:
find ./ -type l -print0 | xargs -0 ls -plah
outputs looks about like this:
lrwxrwxrwx 1 apache develop 99 Dec 5 12:49 ./dir/dir2/symlink1 -> /dir3/symlinkTarget
lrwxrwxrwx 1 apache develop 81 Jan 10 14:02 ./dir1/dir2/dir4/symlink2 -> /dir5/whatever/symlink2Target
etc...
Kindly find below one liner bash script command to find all broken symbolic links recursively in any linux based OS
a=$(find / -type l); for i in $(echo $a); do file $i ; done |grep -i broken 2> /dev/null
You can install "symlinks" package and use the utility
symlinks -rv "/path"
-c == change absolute/messy links to relative
-d == delete dangling links
-o == warn about links across file systems
-r == recurse into subdirs
-s == shorten lengthy links (displayed in output only when -c not specified)
-t == show what would be done by -c
-v == verbose (show all symlinks)
Dangling links are broken ones.
What I do is create a script in my bin directory that is like an alias.
For example I have a script named
lsd
ls -l | grep ^d
you could make one
lsl
ls -lR | grep ^l
Just chmod them +x and you are good to go.

Resources