Hedwin Bonnavaud
Hedwin Bonnavaud

Reputation: 124

Bash Shell file convert .sass ans .scss into css

I'm trying to build a sass workspace.

I - Goal

I have two directories :

/css is a destination directory for /sass files convertion result.

My goal is to code sass or scss in /sass directory, and call a bash file to convert each .sass or .scss file from /sass into a .css result in /css directory.

II - What I did:

[/!\ Maybe useless to read it entirelly, firstly go to the part III which explain the problem.]

Here is my /convert bash file :

SASS_FILES_PATH=sass
CSS_DEST_PATH=css

function get_cleaned_filename {
        # Split fileName to removre file directory:
        IFS='/' # Split delimiter
        read -ra ADDR <<< "$1"
        local ARRAY_LENGTH=${#ADDR[@]}
        RESULT="${ADDR[$ARRAY_LENGTH - 1]}"

        # Split fileName to removre file type:
        IFS='.' # Split delimiter
        read -ra ADDR <<< "$RESULT"
        RESULT="${ADDR[0]}"
}

# function convert_file/1 convert the file in parameter into .css file
# Parameters : $1 : path to source file
# Precondition : file in parameter should have .scss ou .sass extension
#               
# Postcondition : create a .css and a .css.map files that correspond to
#   the converted .sass or .scss file.
function convert_file {
        get_cleaned_filename $f;
        FILENAME=$RESULT;

        #   We can have two files .sass and .scss using the same name :
        if test -f $CSS_DEST_PATH/$FILENAME.css;
        then
            echo "a file $CSS_DEST_PATH/$FILENAME.css exist";
            FILENAME=$FILENAME_2;
            echo "renamed to $FILENAME_2";
        fi
        
        echo "[DEBUG]: sass ${f} ${CSS_DEST_PATH}/${FILENAME}.css";
        sass --trace ${f} ${CSS_DEST_PATH}/${FILENAME}.css;
}

if ! test -f $SASS_FILES_PATH/*.sass || ! test -f $SASS_FILES_PATH/*.scss;
then
    echo "Pas de fichier à convertir dans le dossier, aucune opération n'a été éxécutée.";
else 
    #   Empty CSS_DEST_PATH :
    if test -f $CSS_DEST_PATH/*;
    then 
        for cssFileName in $CSS_DEST_PATH/*;
        do
            rm $cssFileName;
        done
    fi

    #   Convert every .scss and .sass files into .css

    #   If scss file exist in curent directory
    if test -f $SASS_FILES_PATH/*.scss;
    then
        #   Convert each .scss file into css and move it to css directory
        for f in $SASS_FILES_PATH/*.scss;
        do 
            convert_file $f;
        done
    fi

    #   If sass file exist in curent directory
    if test -f $SASS_FILES_PATH/*.sass;
    then
        #   Convert each .sass file into css and move it to css directory
        for f in $SASS_FILES_PATH/*.sass;
        do 
            convert_file $f;
        done
    fi
fi

III - What is the mistake:

In function convert_file\1, i have a mistake :

        echo "[DEBUG]: sass ${f} ${CSS_DEST_PATH}/${FILENAME}.css";
        sass --trace ${f} ${CSS_DEST_PATH}/${FILENAME}.css;

The sass call (second line) return an error:

me@myComputer:~/Desktop/computing/sassWorkshop$ bash convert
[DEBUG]: sass sass/test.scss css/test.css
Traceback (most recent call last):
    7: from /usr/bin/sass:8:in `<main>'
    6: from /usr/lib/ruby/vendor_ruby/sass/exec/base.rb:19:in `parse!'
    5: from /usr/lib/ruby/vendor_ruby/sass/exec/base.rb:52:in `parse'
    4: from /usr/lib/ruby/vendor_ruby/sass/exec/sass_scss.rb:52:in `process_result'
    3: from /usr/lib/ruby/vendor_ruby/sass/exec/base.rb:120:in `process_result'
    2: from /usr/lib/ruby/vendor_ruby/sass/exec/base.rb:182:in `open_file'
    1: from /usr/lib/ruby/vendor_ruby/sass/exec/base.rb:182:in `open'
/usr/lib/ruby/vendor_ruby/sass/exec/base.rb:182:in `initialize': No such file or directory @rb_sysopen - sass/test (Errno::ENOENT)

Note that "convert" is the name of the bash file i use !

The thing i don't understand is that my echo "[DEBUG]: ..." line print that according to my variables, the sass call is "sass sass/test.scss css/test.css". But when i type this line into my terminal, the line works well and my .css file is created.

IV - What i tried:

I tried "rm .sass-cache/ -R" which don't changed anything.

I'm sorry if my post isn't well formed, or if there is many English mistakes (not my mother thong) if it's the case told me please :)

Thanks for any comment than can help me

Upvotes: 0

Views: 423

Answers (1)

L&#233;a Gris
L&#233;a Gris

Reputation: 19675

You should really check your script with shellcheck.net as it contains several errors, mainly due to missing double quotes around variables, use of deprecated test and something that I can't explain:

FILENAME=$FILENAME_2;

The value of the variable FILENAME_2 is not set.

Also: if ! test -f $SASS_FILES_PATH/*.sass || ! test -f $SASS_FILES_PATH/*.scss;

-f does not work with globs, so you need to iterate each globbing to update flags and test each flag, or better use the find command return code

if ! find "$SASS_FILES_PATH/" -name '*.sass' || ! find "$SASS_FILES_PATH/" -name '*.scss'

Useless and dangerous unsecured rm loop:

        for cssFileName in $CSS_DEST_PATH/*;
        do
            rm $cssFileName;
        done

Replace with

        rm -- "$CSS_DEST_PATH/"*

Same issue, cannot test -f with globbing:

    #   If scss file exist in curent directory
    if test -f $SASS_FILES_PATH/*.scss;

This will test files exist and execute the conversion on each entry:

    find "$SASS_FILES_PATH" -name '*.scss" -o -name '*.sass' -exec convert {} \;

Your function to clean file-name is suboptimal:

function get_cleaned_filename {
        # Split fileName to removre file directory:
        IFS='/' # Split delimiter
        read -ra ADDR <<< "$1"
        local ARRAY_LENGTH=${#ADDR[@]}
        RESULT="${ADDR[$ARRAY_LENGTH - 1]}"

        # Split fileName to removre file type:
        IFS='.' # Split delimiter
        read -ra ADDR <<< "$RESULT"
        RESULT="${ADDR[0]}"
}

Instead:

function get_cleaned_filename {
        filename="${1##*/}"    # remove leading directories path
        echo "${filename%\.*}" # remove dot suffix
}

Then in convert_file:

function convert_file {
        FILENAME="$(get_cleaned_filename "$1")";

Finally, this may do what you want:

find sass/ -type f \( -name '*.scss' -o -name '*.sass' \) -exec bash -c 'src="$0"; _tdest="/${0%\.*}"; dest="css/${_tdest##*/}.css"; rm -f "$dest"; sass --trace "$src" "$dest"' {} \;

or

#!/usr/bin/env bash

find sass/ -type f \( -name '*.scss' -o -name '*.sass' \) -exec bash -c '
  # Source file (.scss or .sass) passed as argument 0
  src="$0" 

  # Strip-out file name extension
  _tdest="/${0%\.*}"

  # Construct destination file path/name.css
  dest="css/${_tdest##*/}.css" # Construct destination file path/name.css

  # Remove destination file if it exists
  rm -f "$dest"

  # Perform the scss|sass compilation
  sass --trace "$src" "$dest"
' {} \;

Upvotes: 1

Related Questions