0

So, i create a bash script that search recursively for files that includes the words that you introduce, then creates a folder (if the folder does not exist) with the same name as the variable introduced and finally it copies all the files that meet the word in that new folder.

So for example, if i have a folder named "files_1906" and inside i have a file named "hello_1906.pdf" and then another folder (not inside the first) named "hello" and inside a file named "1906hello" and if i introduce: .sh program_name.sh "1906" it should create a folder named 1906 and copy the two files inside.

but right now i only managed to create the folders, it doesn't copy the files.

here is the full code:

#!/bin/bash
currentDir=$(pwd)
for var in "$@"
do
    countCurrentWord=$(find . -type f -name "$var" | grep "$var" | wc -l)
    echo -e "$countCurrentWord"
    echo -e "Number of files matching the keyword $var: $countCurrentWord"
    if [[ $countCurrentWord -gt 0 ]]
    then
        if [[ -d $currentDir/$var ]]
        then
            echo -e "the folder $var already exists, copying the files...\n"
        else
            mkdir "$currentDir"/"$var"
            echo -e "the folder $var does not exist, creating the folder and copying the files...\n"
        fi
        IFS=$'\n'
        array=$(find . -type f -name "$var")
        declare -p array > /dev/null 2>&1
        declare -a array > /dev/null 2>&1
        length=${#array[@]}
        for ((i=0; i < length; i++))
        do
            cp "${array[i]}" "$currentDir"/"$var"/ > /dev/null 2>&1
            echo -e "hello world"
        done
    else
        echo -e "no files found, no move will be made.\n"
    fi
done

the console returns the following:

first it says that $countCurrentWord = 0, which doesn't make any sense cause there are files that contains "1906"

but here is where this get's trippy:

the program ignores the greater than 0 and starts the loop, creating the folder called 1906, but after, it doesn't copy the file, it remains empty once is created. I get also the hello world from the second loop.

So, how can we fix this so that it does its job and copies the files?

i already tried with files named only "1906" (also does not work), but the script should be capable of reading the full name of a file and discern if contains the keyword introduced. i don't know if i have a typo or anything, i'm not experienced in scripting in bash

I hope i explained this well enough so you guys can help me, thank you for your effort!

  • 1
    You need spaces around the elements of a `[[ ]]` conditional expression: `[[ $countCurrentWord -gt 0 ]]` (without them it's doing something completely different from what you want). Also, please edit the question to put the code in [code block format](https://meta.stackoverflow.com/q/251361) (either indent by 4 spaces, or surround with triple-backticks) so it's readable. I'd also recommend avoiding `echo -e` whenever possible (some versions print the "-e" as output), and running the code through [shellcheck.net](https://www.shellcheck.net/) and fixing what it points out. – Gordon Davisson Dec 13 '22 at 10:39
  • 1
    This doesn't create an array: `array=$(find . -type f -name "$var")`. Also, it won't work if filenames contain newline characters. Your strategy is flawed. Something like this would be much simpler and more accurate: `find . -type f -name "$var" -exec cp {} /path/to/destination/dir/ \;` – M. Nejat Aydin Dec 13 '22 at 10:40
  • 1
    Please remove all unnecessary blank lines. – Cyrus Dec 13 '22 at 10:45
  • edited the spaces so now the condition is not matched and it doesn't loop, but the other problem remains, i'm searching for keywords that exists, it should find them and be "gt-0" – Joel Garcia Hurtado Dec 13 '22 at 10:53
  • Your script still has syntax errors. You can see them by pasting the script in [shellcheck](https://www.shellcheck.net/). It will also point out code smells left in your code – Aserre Dec 13 '22 at 12:41
  • 1
    `find . -type f -name "$var" | grep "$var" | wc -l` will only find files named exactly $var, the grep does nothing, then it counts the number found. What are you expecting it to do? Did you test your code at all? – stark Dec 13 '22 at 12:50
  • As i writed "i already tried with files named only "1906" (also does not work), but the script should be capable of reading the full name of a file and discern if contains the keyword introduced" why is that? cause i've seen this programm work in a different system with only few changes with the same find, so yes, i tested it – Joel Garcia Hurtado Dec 13 '22 at 12:58
  • Should [this answer](https://stackoverflow.com/a/37396585/1765658) meet your need? Something like `find ... -exec cp -ait /path/to/target {} +` – F. Hauri - Give Up GitHub Dec 13 '22 at 13:37
  • @M.NejatAydin Have a look at [my answer](https://stackoverflow.com/a/74786047/1765658) for a reliable way of storing special filenames into a bash array. – F. Hauri - Give Up GitHub Dec 13 '22 at 14:10
  • @stark That depends on the value of `$var`; if it expands to `*.txt`, then the `find` command will be looking for files whose name ends in `.txt`. Using `$var` with both `find` and `grep` is wrong, because `find` treats it as a glob while `grep` treats it as a regular expression. (`wc -l` is unnecessary because you can just use `grep -c "$var"` to get the number of matches). – chepner Dec 13 '22 at 14:12

1 Answers1

0

The following adaptation of your script includes a revamped loop for assignment of array elements.

It also adds logic to test and respond to some conditions which may, or may not, be problematic.

#!/bin/bash

DBG=0

FLUSH=0
PURGE=0

while [ $# -gt 0 ]
do
    case "${1}" in
        --flush ) FLUSH=1 ; shift ;;
        --purge ) PURGE=1 ; shift ;;
        --* ) echo -e "\n[SYNTAX] Invalid option provided on the command line.  Only valid options: [ --flush ] \n Bye!\n" ; exit 1 ;;
        * ) break ;;
    esac
done

SELECT="itemsFound.txt"
currentDir=$(pwd)

for var in "$@"
do
    if [[ -f "${currentDir}/${var}/" ]]
    then
        echo -e "\nERROR - Name conflict for directory '${currentDir}/${var}/':"
        ls -l "${currentDir}/${var}" 2>&1 | awk '{ printf("\t %s\n", $0 ) ; }'
        echo -e "\nAborting.\n" ; exit 1
    fi

    if [[ -d "${currentDir}/${var}/" ]]
    then
        echo -e "\nThe folder '${var}' already exists ..."
        if [ ${FLUSH} -eq 1 ]
        then
            echo -e "\nPurging files previously placed in that folder ..."
            ( cd "${currentDir}/" ; rm -vf "${var}/"* 2>&1 | awk '{ printf("\t %s\n", $0 ) ; }' )
        fi
        if [ ${PURGE} -eq 1 ]
        then
            echo -e "\nPurging old folder ..."
            rmdir -v "${currentDir}/${var}/" 2>&1 | awk '{ printf("\t %s\n", $0 ) ; }'
        fi
    fi

    find . -type f -name '*'"${var}"'*' -print | grep -v "/${var}/" | sort >"${SELECT}"

    countCurrentWord=$(wc -l "${SELECT}" | awk '{ print $1 }' )

    if [[ "${countCurrentWord}" -gt 0 ]]
    then
        echo -e "\nNumber of files matching the keyword '${var}': ${countCurrentWord}"

        if [[ ! -d "${currentDir}/${var}/" ]]
        then
            echo -e "\nThe folder '${var}' does not exist, creating the folder ..."
            mkdir -v "${currentDir}/${var}/" 2>&1
            if [[ $? -ne 0 ]]
            then
                echo -e "\n[NO DIRECTORY] Failed to create directory '${currentDir}/${var}/'.  Aborting.\n" ; break
            fi
        fi
        echo -e "Copying the files..."

        array=()
        while read -r line
        do
            array+=("${line}")
        done <"${SELECT}"

        length=${#array[@]}
        test ${DBG} -eq 1 && echo "Array size = ${length} ..."

        for ((i=0; i < length; i++))
        do
            test ${DBG} -eq 1 && {
                ls -l ${array[${i}]} 2>&1 | awk '{ printf("\t %s\n", $0 ) ; }'
                echo "array[$i] = ${array[${i}]}"
            }
            cp -v "${array[${i}]}" "${currentDir}/${var}/" 2>&1 | awk '{ printf("\t %s\n", $0 ) ; }'
        done
        echo -e "\nCONTENTS of '${currentDir}/${var}/' :"
        ls -l "${currentDir}/${var}/" 2>&1 | awk '{ printf("\t %s\n", $0 ) ; }'
    else
        echo -e "[NO ACTION] Count matching the keyword '${var}': ${countCurrentWord}\n"
    fi
done

Session log looks like this:

ericthered:/0__WORK$ ./test_89.sh --flush --purge Output

The folder 'Output' already exists ...

Purging files previously placed in that folder ...
     removed 'Output/awkSystemCommandOutputImport.sh'
     removed 'Output/OutputPrefix__col1_01.csv'
     removed 'Output/OutputPrefix__col1_02.csv'
     removed 'Output/OutputPrefix__col1_03.csv'
     removed 'Output/OutputPrefix__col1_04.csv'
     removed 'Output/OutputPrefix__col1_05.csv'
     removed 'Output/OutputPrefix__col1_06.csv'

Purging old folder ...
     rmdir: removing directory, '/DB001_F5/WORK__ScriptIntegration/0__WORK/Output/'

Number of files matching the keyword 'Output': 7

The folder 'Output' does not exist, creating the folder ...
mkdir: created directory '/DB001_F5/WORK__ScriptIntegration/0__WORK/Output/'
Copying the files...
     './OutputPrefix__col1_01.csv' -> '/DB001_F5/WORK__ScriptIntegration/0__WORK/Output/OutputPrefix__col1_01.csv'
     './OutputPrefix__col1_02.csv' -> '/DB001_F5/WORK__ScriptIntegration/0__WORK/Output/OutputPrefix__col1_02.csv'
     './OutputPrefix__col1_03.csv' -> '/DB001_F5/WORK__ScriptIntegration/0__WORK/Output/OutputPrefix__col1_03.csv'
     './OutputPrefix__col1_04.csv' -> '/DB001_F5/WORK__ScriptIntegration/0__WORK/Output/OutputPrefix__col1_04.csv'
     './OutputPrefix__col1_05.csv' -> '/DB001_F5/WORK__ScriptIntegration/0__WORK/Output/OutputPrefix__col1_05.csv'
     './OutputPrefix__col1_06.csv' -> '/DB001_F5/WORK__ScriptIntegration/0__WORK/Output/OutputPrefix__col1_06.csv'
     './WORKS/awkSystemCommandOutputImport.sh' -> '/DB001_F5/WORK__ScriptIntegration/0__WORK/Output/awkSystemCommandOutputImport.sh'

CONTENTS of '/DB001_F5/WORK__ScriptIntegration/0__WORK/Output/' :
     total 28
     -rwxr-x--- 1 ericthered ericthered 2159 Dec 17 18:31 awkSystemCommandOutputImport.sh
     -rw-rw-r-- 1 ericthered ericthered  150 Dec 17 18:31 OutputPrefix__col1_01.csv
     -rw-rw-r-- 1 ericthered ericthered   50 Dec 17 18:31 OutputPrefix__col1_02.csv
     -rw-rw-r-- 1 ericthered ericthered  150 Dec 17 18:31 OutputPrefix__col1_03.csv
     -rw-rw-r-- 1 ericthered ericthered   50 Dec 17 18:31 OutputPrefix__col1_04.csv
     -rw-rw-r-- 1 ericthered ericthered  100 Dec 17 18:31 OutputPrefix__col1_05.csv
     -rw-rw-r-- 1 ericthered ericthered  150 Dec 17 18:31 OutputPrefix__col1_06.csv
ericthered:/0__WORK$ 
Eric Marceau
  • 1,601
  • 1
  • 8
  • 11