-1

I'm trying to write a Bash Script that will create symlinks but exclude certain files.

I already looked up this thread but it doesn't help me:

https://serverfault.com/questions/165484/how-to-symlink-folders-and-exclude-certain-files

So this is the script I'm using at the moment:

#! /bin/bash
target=/home/csgo/game/output
cs=/home/csgo/game/csgo-deagle1

exclude=( "*.conf" "*.cfg" "*txt" "*.ini" "*.smx" "*.mp3" "*.sh" )    

for file in ${cs}; do
    for (( index = 0; index < ${#exclude[@]}; index++ )); do
        if [[ ${file} != ${exclude[${index}]} ]]; then
            ln -s ${file} ${target}
        elif [[ ${file} == ${exclude[${index}]} ]]; then
            cp ${file} ${target}
        fi 
    done
done

The script should look in the exclude list and if the extension is excluded it should not make a symlink; it should copy the file into place instead.

At the moment the script creates a symlink of the directory but everything inside it is copied.

Community
  • 1
  • 1
  • As a side note, the `elif` is superfluous. The `if` already evaluated the condition and the `cp` should simply be in an `else` branch. No need to test for the same thing again. – tripleee Jun 24 '15 at 06:25
  • More tangentially, `${file}` is equivalent to `$file` and the braces are only necessary and useful when you need to interpolate a variable in the middle of some other text, like `foo${file}bar` vs `foo$filebar` (where the latter would refer to a presumably nonexistent variable `$filebar`) – tripleee Jun 24 '15 at 07:41

1 Answers1

1

You are comparing against the literal strings in the exclude list. The file name is not literally equivalent to *.conf so the comparison returns false.

Anyway, I would skip the array and just use case.

#! /bin/bash

# I don't see the value of these variables, but more power to them
target=/home/csgo/game/output
cs=/home/csgo/game/csgo-deagle1

# Hmmm, this will only loop over the actual directory name.
# Do you mean for file in "$cs"/* instead?
for file in $cs; do
    case $file in
      *.conf | *.cfg | *txt | *.ini | *.smx | *.mp3 | *.sh )
        cp "$file" "$target";;
      * )
        ln -s "$file" "$target";;
    esac
done

Notice also the proper quoting of "$file" and, generally, any variable which contains a file name.

(There is now nothing Bash-specific in this script, so you could change the shebang to #!/bin/sh, too.)

A less intrusive change would be to use =~ instead, but then you have to switch to regexes instead of glob patterns for the exclude list. But the approach above is more efficient as well, as it avoids the explicit inner loop.

Community
  • 1
  • 1
tripleee
  • 175,061
  • 34
  • 275
  • 318
  • I assumed the `*txt` without a dot before the extension was not a typo; if it was, obviously, you'll want to correct it. – tripleee Jun 24 '15 at 06:27
  • Mhm maybe my Explanation was bad. I have one directory it's the Master Directory. The Script should check every file in the directory and should create a Symlink of it. When the file is for example a config File like "test.cfg" or something else listed in the Exclude List it should copy it instead. The Output of the Symlinked Files and Copied Files should go in the Output Directory. Im not this good in Bash so this is very hard for me :D – tilloo3 Jun 24 '15 at 06:45
  • Apart from the bug in your original script which I have commented on in the code (loop over the files in the directory, rather than just the directory name) I believe this should meet your requirements. If it fails, how does it fail? – tripleee Jun 24 '15 at 06:53
  • Okay so i replaced the Script with the edited Version but it doesnt seemed to make any changes. It creates a Symlinked Folder in the Output Directory but everything in it is not symlinked. In the main Scipt from the Thread they used the Symlink Command like this: ln -s ${file} ${target}/${file} I dont know if this helps – tilloo3 Jun 24 '15 at 07:13
  • If you didn't make the change to use `for file in "$cs"/*` then that's the thing you still need to sort out. You'll need to remove the symlink to the source directory before you try again, obviously. – tripleee Jun 24 '15 at 07:36
  • Modulo the quoting issues, `ln -s ${file} ${target}/${file}` is equivalent to `ln -s "$file" "$target"` as long as `$target` points to an existing directory. – tripleee Jun 24 '15 at 07:38
  • Okay so now something changed. The Script created now a Symlink of the the Direcotorys inside the Main Directory and copied the .sh Files but everything inside the Folders that are in the Main Directory is still copied. I hope that is understandable. So it seems like it has only gone through the Main Directory but everything that is in the Sub Directorys are not touched. Is that the correct form ? (I copied it out of the Quotes) ' for file in "$cs"/*; do ' – tilloo3 Jun 24 '15 at 07:57
  • Sounds like you *didn't* remove the symlink before trying again? If `$target` already exists, and is a symlink back to `$source`, then that would produce the results (I think) you are describing. You need to remove any existing symlink before running this (or rather, make sure that the destination directory exists, and is a separate, regular directory). – tripleee Jun 24 '15 at 09:59
  • No i deleted the Symlink by deleting all files in it i even removed the directory and created it new. But that dont works. I created a completly new directory and changed the Target in the Script. After i started the Script the Main Directory is symlinkend. The Files and Directorys are too. But when i enter a Subdirectory nothing is symlinked the all have the same size / color in bash as before. – tilloo3 Jun 24 '15 at 10:14
  • There is nothing here which descends into subdirectories. The script simply loops over each entry in the source directory, either copying or symlinking it (and given what's on the exclude list, I guess all your subdirectories will be symlinked, as their names will most likely not match anything on the exclude list). If you require a recursive solution which examines the contents of any subdirectories, that is going to be slightly more complex (but you already have all the parts -- just add a special case for directories). – tripleee Jun 24 '15 at 10:15
  • Yea thats what i need a Recursive Solution ! :) Yep every Dirctory in it is linked thats right. How can i make the Special Case for the directories ? – tilloo3 Jun 24 '15 at 10:24
  • That's IMHO already far outside the scope of this question. Basically, `if [ -d "$file" ]; then recurse` -- you should easily find many near-duplicates, but in the worst case, post a new, separate question (though by all means do link back here for context). – tripleee Jun 24 '15 at 12:00