Script bulk symlink creation with rename

mscottblake
Valued Contributor

I have a postscript that is creating symlinks of all the apps in a folder and placing them somewhere else on the system. This is working perfectly, but I was also hoping to change the names slightly.

For the sake of simplicity, the first 6 and last 4 characters of each are the same and that's what I'm hoping to remove.

I was hoping to do it all in 1 pass, but I have been unsuccessful so far. Here is my current 1 liner:```
ln -s /path/to/apps//.app /new/path/to/symlinks
```

I've played around with sed, but I can't get it to work because there's an intermediate directory in between the base and the .app files. If it weren't for that, this would be simple.

Any gurus want to take a crack?

4 REPLIES 4

rmanly
Contributor III

So you are starting with something like:

/path/to/apps/123456foo1234.app
/path/to/apps/123456bar1234.app
/path/to/apps/123456baz1234.app

and you want the symlinks to be:

/new/path/foo.app
/new/path/bar.app
/new/path/baz.app

Am I understanding this correctly?

Unfortunately we don't have access to bash 4 in OS X by default because this is fairly trivial with the availability of Python style "slicing" with negative numbers from the end. But in bash 3 we can do this like so:

for app in ./1/*/*.app; do
    filename="${app##*/}"
    name=$(sed -E 's/^.{6}//;s/.{8}$//' <<< "${filename}")
    ln -s "${app}" ./2/test/"${name}"
done

the $filename assignment uses bashes built-in parameter expansion to strip off everything up to and including the last /

the process substution in the $name assignment is doing two sed operations. The first strips a certain number of characters from the beginning and the second strips from the end

then we just do the symlinks. you can make the end of this ${name}.app" if you wish.

$ ls -la 1/test1/
total 0
drwxr-xr-x  4 ryan  staff  136 Sep 27 09:02 .
drwxr-xr-x  4 ryan  staff  136 Sep 27 09:02 ..
-rw-r--r--  1 ryan  staff    0 Sep 27 09:01 123456baz1234.app
-rw-r--r--  1 ryan  staff    0 Sep 27 09:01 123456foo1234.app
$ ls -la 1/test2/
total 0
drwxr-xr-x  3 ryan  staff  102 Sep 27 09:02 .
drwxr-xr-x  4 ryan  staff  136 Sep 27 09:02 ..
-rw-r--r--  1 ryan  staff    0 Sep 27 09:01 123456bar1234.app
$ ls -la 2/test/
total 0
drwxr-xr-x  2 ryan  staff   68 Sep 27 09:26 .
drwxr-xr-x  3 ryan  staff  102 Sep 27 09:02 ..
$ for app in ./1/*/*.app; do filename="${app##*/}"; name=$(sed -E 's/^.{6}//;s/.{8}$//' <<< "${filename}"); ln -s "${app}" ./2/test/"${name}"; done
$ ls -la 2/test/
total 24
drwxr-xr-x  5 ryan  staff  170 Sep 27 09:28 .
drwxr-xr-x  3 ryan  staff  102 Sep 27 09:02 ..
lrwxr-xr-x  1 ryan  staff   27 Sep 27 09:28 bar -> ./1/test2/123456bar1234.app
lrwxr-xr-x  1 ryan  staff   27 Sep 27 09:28 baz -> ./1/test1/123456baz1234.app
lrwxr-xr-x  1 ryan  staff   27 Sep 27 09:28 foo -> ./1/test1/123456foo1234.app

I hope this is what you were after :)

mscottblake
Valued Contributor

@rmanly This was a great start. Instead of the 1234 at the end, I was going to strip the .app off the name to shave a bit off in finder. These file names are rather long and when they get condensed, it's hard to tell which is which.

I'm not in the office today to be able to try this out for real, but in my initial testing, this now works. I modified your script to ```
for app in $(pwd)/1//.app; do filename="${app##*/}" name=$(sed -E 's/^.{6}//;s/.app$//' <<< "${filename}") ln -s "${app}" ./2/test/"${name}"
done
```

In order for the symlinks to be valid, the full path needed to be provided in the for loop. It is also removing the .app from the end of the name now.

I can't wait to test this out for real on Monday :)

mscottblake
Valued Contributor

In case anyone may be wondering; I was asked to simplify the Adobe CC installation on our public machines. What I'm doing is finding all the applications from /Applications/AdobeCC (our installation directory) and creating a single list of symlinks in /Applications/Adobe, then hiding the /Applications/AdobeCC directory with ```
chflags hidden /Applications/AdobeCC
```
I was able to do just that with little effort, but then I was asked to shorten the names since they ALL start with "Adobe " and since they are now symlinks, they don't need the ".app" at the end. Hopefully this will be acceptable as I can't make them any shorter.

This has been a fun little project.

rmanly
Contributor III

So given that all you were trying to get rid of was the .app extension we can actually simplify things a bit and let bash do all the work. I am also going to change the variable names for clarity (hopefully).

for app_path in ./1/*/*.app; do
    filename="${app_path##*/}"
    full_name="${filename%.*}"
    short_name="${full_name:6}"
    ln -s "${app_path}" ./2/test/"${short_name}"
done