Search code examples
bashawksedgrep

Grep for string from multiple file paths from list of files


I am currently learning bash scripting, wanted help in following issue.

There are 3 files containing list of file paths inside them: list1, list2, list3.

list1 contains paths of multiple txt paths.

list2 contains paths of multiple cfg paths.

list3 contains paths of multiple bat paths.

Example:

list1:
./saved/nametxts/ptboy1.txt
./saved/nametxts/ptboy2.txt
./saved/nametxts/ppboy1.txt
./saved/nametxts/ppboy2.txt
./saved/nametxts/pgboy_a.txt

list2:
./saved/configs/names/ptboy1.cfg
./saved/configs/names/ptboy2.cfg
./saved/configs/names/ppboy1.cfg
./saved/configs/names/ppboy2.cfg
./saved/configs/names/pgboy_a.cfg

list3:
./saved/batches/confignames/ptboy1.bat
./saved/batches/confignames/ptboy2.bat
./saved/batches/confignames/ppboy1.bat
./saved/batches/confignames/ppboy2.bat
./saved/batches/confignames/pgboy_a.bat

I want to grep for

a name John from the files listed in list1

an ID HS_J_1024 from files listed in list2 and

profile history hist_1024 from files listed in list3

Hence, from the above example,

John is searched in ./saved/nametxts/ptboy1.txt and other following textfiles from list1

HS_J_1024 is searched in ./saved/configs/names/ptboy1.cfg and other following cfgfiles from list2

hist_1024 is searched in ./saved/batches/confignames/ptboy1.bat and other following batfiles from list3

User will give only path for these lists, such as:-

./saved/namelists/list1

./saved/cfglists/list2

./saved/batlists/list3

Then grep for name, ID and profile in all the files one by one.

Once name, ID, profile matches - the Bat file would get updated with:

"grepped today " at the end of batfile.

What I have tried now:

#!/bin/bash

read -p "Enter name list file path: " filename
read -p "Enter CFG list file path: " filecfg
read -p "Enter bat list file path: " filebat

echo $filename
echo $filecfg
echo $filebat

#making one line through paste
paste $filename $filecfg $filebat > pastefile

#awk -F ' ' '{print $1 ":" $2}' pastefile
#file="pastefile"

while IFS= read -r line; do
    echo "$line" > printline
    #there are 3 parts (filepaths) - storing them one by one in a1(names), a2(cfg), a3(bat)
    awk '{print $1}' printline > a1
    awk '{print $2}' printline > a2
    awk '{print $3}' printline > a3
    chmod +x a1,a2,a3
    echo "grep -A 2 'John' a1 | sed 's?.............\$??' > a11" > a11
    echo "grep 'HS_J_1024' a2 > a12" > a12
    echo "grep 'hist_1024' a3 | sed -i 's?\$?grepped today?' a3" > a13
    chmod +x a11,a12,a13
    ./a11
    ./a12
    ./a13
done <pastefile

Here files a1, a2, a3 are having proper file paths but the same is not reflecting when I try to grep. I am missing something to make this an input to the grep.

Could you please help me out? I would grateful if you could suggest any other optimal way of doing this too.

Thank you

Note: searching in the files listed in list1, list2 and list3, not in list1, list2 and list3 themselves.


Solution

  • If, as in your example, your file names do not contain white spaces, you can try:

    read -p "Enter name list file path: " filename
    read -p "Enter CFG list file path: " filecfg
    read -p "Enter bat list file path: " filebat
    read -p "Enter first string to search for: " s1
    read -p "Enter second string to search for: " s2
    read -p "Enter third string to search for: " s3
    
    while read -r a1 a2 a3; do
      if grep -qF "$s1" "$a1" && grep -qF "$s2" "$a2" && grep -qF "$s3" "$a3"; then
        printf 'grepped today\n' >> "$a3"
      fi
    done < <(paste "$filename" "$filecfg" "$filebat")
    

    If your file names can indeed contain white spaces you can store the content of your 3 files in bash arrays with mapfile and use these arrays in your loop:

    mapfile -t l1 < "$filename"
    mapfile -t l2 < "$filecfg"
    mapfile -t l3 < "$filebat"
    
    for (( i=0; i<${#l1[@]} && i<${#l2[@]} && i<${#l3[@]}; i++ )); do
      if grep -qF "$s1" "${l1[i]}" && grep -qF "$s2" "${l2[i]}" && grep -qF "$s3" "${l3[i]}"; then
        printf 'grepped today\n' >> "${l3[i]}"
      fi
    done