Share your knowledge at the LQ Wiki.
Go Back > Forums > Non-*NIX Forums > Programming
User Name
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.


  Search this Thread
Old 06-01-2012, 08:50 PM   #1
LQ Newbie
Registered: Mar 2012
Posts: 16

Rep: Reputation: Disabled
Make multiples links with a parameter (Bash & Perl)

Hi, I try to make several links (all files in /my_path/*) in one location (/usr/local/bioinfo) in one step, to do that I create a script "links"

I try this, and that work

PHP Code:
cd /usr/local/bioinfo/
echo -
"Write the path"
read path
for i in my $path
ln -"$i" "${t%.*}"
But I want to execute a script with a parameter (ex. -path), like this:

./links -path /my_path/*
How can I do that?

PD: Somebody can say me how do that in perl, I have to use STDIN but the rest I have no idea.



Last edited by Trotel; 06-01-2012 at 08:55 PM.
Old 06-01-2012, 10:17 PM   #2
Nominal Animal
Senior Member
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 947Reputation: 947Reputation: 947Reputation: 947Reputation: 947Reputation: 947Reputation: 947Reputation: 947
Say you save the following script as args:

for ARG in "$@" ; do
    printf 'Argument "%s"\n' "$ARG"
What happens when you run ./args /somewhere/*

The shell will first apply parameter expansion. It sees that the second item is a glob pattern, and will expand it to the list of all matching files. If you have files /somewhere/one and /somewhere/two, then the output will be
Argument "/somewhere/one"
Argument "/somewhere/two"
In other words, the script does not need to worry about locating the files, as the shell will do it for you.
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

I would approach the problem in a different way. I'd expect my script to take at least two parameters, the first parameter being the directory to create the links in, and all others would be the desired symlink targets, absolute or relative to current directory. You could then use tab expansion in most shells to find both the link directory, and the symlink target files.

The one issue with that approach is that both are specified as relative to current directory, whereas for the ln command, the symlink target is always relative to the symlink itself. In other words, we get/know some-path-to-A and some-path-to-B, but need to supply from-A-to-B to ln -s.

The beginning of the script is simple. If there are not enough parameters, then output usage. (Although I am using Bash, I tend to use POSIX shell idioms. Others will recommend Bash-specific replacements. If you only use Bash for scripting, go with Bash; I'm a crufty curmudgeon.)

# Make sure locale is POSIX, so we do not choke on non-UTF8 file names in UTF-8 locales.
export LANG=C
export LC_ALL=C

# Use / as the input field separator.

# Output help if not enough parameters or -h or --help specified.
if [ $# -lt 1 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
    exec >&2
    echo ""
    echo "Usage: $0 -h | --help"
    echo "       $0 LINK-DIRECTORY TARGET(s).."
    echo ""
    echo "This script will create a symlink to each TARGET in LINK-DIRECTORY."
    echo ""
    exit 0
Next, we remove the link directory from the parameter list, and shift the rest one place up.
# Pop the link directory from the parameter list.
shift 1
To find where it actually leads, I use a subshell to change to that directory, then run /bin/pwd to find out its actual path, and capture it to a variable. If it fails -- say, the directory does not exist --, cd will output an error message, and we can just abort the script.
# Find out the path to link directory. If it is not a real directory, abort.
LINKPATH="$(cd "$LINKDIR" && /bin/pwd)" || exit $?
Next, we loop over all leftover parameters. This way we only need to worry about the current link within the loop:
# Loop over all other arguments. (The link directory was shifted out.)
for TARGET in "$@" ; do

    # Verify the target exists.
    if [ ! -e "$TARGET" ]; then
        echo "$TARGET: No such file or directory." >&2
        exit 1
Next, we split the target into the file name part (which will be the symlink name, of course), and the actual path. For the path I use the same /bin/pwd trick as earlier, except this time I suppress the error message cd might produce by redirecting standard error to /dev/null:
    # Filename part of target,
    TARGETFILE="$(basename "$TARGET")"

    # and full path part of target.
    if ! TARGETPATH="$(cd "$(dirname "$TARGET")" 2>/dev/null && /bin/pwd)" ; then
        echo "$TARGET: Directory does not exist." >&2
        exit 1
Next comes the tricky bit. I construct two strings, the first of which describes the directories that need to be ascended from the link directory, and the second describes the path to then descend, to get from link directory to target:
    # The list of directories needed to ascend first from link dir,
    # then to descend down to target dir.
Since there is no reason to ascend a directory if you'll immediately descend into it anyway, we can remove the leading common path segments from both:
    # Remove leading common directories from uplist and downlist.
    while [ "${uplist%%/*}" = "${downlist%%/*}" ] && [ -n "$uplist" ] && [ -n "$downlist" ]; do
        [ "$olduplist" = "$uplist" ] && uplist=""

        [ "$olddownlist" = "$downlist" ] && downlist=""
If there are no slashes, then ${var#*/} evaluates to ${var} (i.e. no change!) so we need to explicitly check if there were no slashes. It is easiest to do by comparing against the unmodified value.

Next, we can construct the actual path. Start with ./ so that there will always be a trailing slash. We can remove it after the path is constructed:
    # The symlink starts at the link directory.

    # The symlink the ascends each directory up from the link directory,
    LINK=".$(echo "/$uplist/" | sed -e 's|[^/]\+|..|g; s|//\+|/|g')"

    # then descends down into the target directory and item.

    # Remove the superfluous "./" at the start of the symlink,
    # as well as any trailing slashes.
Now $LINK is the path from the link directory to the target item. So, create the symlink:
    # Create the symlink; abort if failure.
    ln -s "$LINK" "$LINKPATH/$TARGETFILE" || exit $?
That's it. If you run the script with some test arguments, you'll see that the symlinks are always relative; this is due to the path walking tricky part in the middle. It is also what makes the script useful compared to just using plain ln -s .

Note that the above script uses POSIX idioms for a reason: it should run using dash too, not just Bash (by changing only the first line to #!/bin/dash ). If you always have Bash at your fingerprints, you can clean up the syntax quite a bit using Bash-only features. Like I said, I'm just stuck in my ways. For now.

For debugging, I recommend you modify the second-to-last line to echo ln -s , and perhaps sprinkle some informative echo or printf lines here and there. (printf is supported by both Bash and POSIX shells; use echo only for unformatted string output.)

Hope you find this informative,
Old 06-04-2012, 01:13 PM   #3
LQ Newbie
Registered: Mar 2012
Posts: 16

Original Poster
Rep: Reputation: Disabled
I forgot to tell you that I am beginner, can you explain me in simple words
Old 06-05-2012, 06:36 PM   #4
Senior Member
Registered: Mar 2004
Location: england
Distribution: Debian, Mint, Puppy, Raspbian
Posts: 3,421

Rep: Reputation: 200Reputation: 200Reputation: 200
what is wrong with:

ln -s my_path/* /usr/local/bioinfo
Old 06-05-2012, 09:06 PM   #5
LQ Newbie
Registered: Mar 2012
Posts: 16

Original Poster
Rep: Reputation: Disabled
Originally Posted by bigearsbilly View Post
what is wrong with:

ln -s my_path/* /usr/local/bioinfo
The link is broken
Old 06-06-2012, 10:30 AM   #6
Senior Member
Registered: Dec 2004
Location: Marburg, Germany
Distribution: openSUSE 13.1
Posts: 1,330

Rep: Reputation: 254Reputation: 254Reputation: 254
ln will create the entries you specify. To avoid broken links you can execute it directly inside the target directory:
$ mkdir demo
$ touch demo/a
$ touch demo/b
$ touch demo/c
$ mkdir target
$ cd target
$ ln -s ../demo/* .
$ ls -lh
total 0
lrwxrwxrwx 1 reuti users 9 2012-06-06 17:23 a -> ../demo/a
lrwxrwxrwx 1 reuti users 9 2012-06-06 17:23 b -> ../demo/b
lrwxrwxrwx 1 reuti users 9 2012-06-06 17:23 c -> ../demo/c


link, script

Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] bash & perl - script adjustment webhope Programming 10 05-24-2010 06:51 AM
how to pass in a parameter to a perl script new_2_unix Linux - Newbie 2 12-09-2007 12:48 AM
linux bash - how to use a dynamic parameter in shell parameter expansion expression nickleus Linux - General 2 08-21-2006 04:54 AM
bash & perl scripts scribbler001 Programming 1 04-26-2005 04:56 AM
Perl parameter dvong3 Programming 3 02-21-2004 10:03 AM > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 12:58 PM.

Main Menu
Write for LQ is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration