Saturday, February 19, 2022

[SOLVED] Grep -rl from a .txt list

Issue

I'm trying to locate a list of strings from a .txt file, the search target is a directory of multiple .csv (locating which .csv contain the string)

I already find how to do it manually: grep -rl doggo C:\dirofcsv\ The next step is to to it from a list of hundreds of terms.

I tried grep -rl -f list.txt C:\dirofcsv < print.txt but I only have the last term printed.. I want to have the results lines by lines.

I'm missing something but I don't know where. I'm working on windows with a term emulator.

EDIT: I've found how to list the terms from a file.Now I need to see which terms have which result like " doggo => file2, file4" did I need to write a loop ?

Thanks community.


Solution

I think you meant to pass the command as:

grep -rl -f list.txt C:\dirofcsv >> print.txt

Give it a shot. It should take all patterns from list.txt line by line and search in the directory C:\dirofcsv for files with matching patterns and print their names to print.txt file.

Try this for printing without a loop (just like you asked in comments ;-)

One Line Answer

dir=C:\dirofcsv
listfile=list.txt

eval $(jq -Rsr 'split("\n") | map(select(length > 0)) | reduce .[] as $line ([]; . + ["echo \($line) :; grep -rl \($line) \($dir); echo"]) | (join("; "))' --arg dir "$dir" < "$listfile")

Another solution, for explanation say:

unset li
readarray li -u <"$listfile"
quoted_commands="$(jq -R 'reduce inputs as $line ([]; . + ["echo \($line) :; grep -rl \($line) \($dir); echo"]) | (join("; "))' \
    --arg dir $dir \
    <<< $(echo; printf "%s" "${li[@]}"))"
quoted_commands=${quoted_commands%\"}
commands=${quoted_commands#\"}
eval $commands

Breaking down the command for better explaination in comments:

# read contents of listfile in li
unset li && readarray li -u <"$listfile"

# add the content to new list so that it prints the list elements in new-lines
# also add a newline at top as it will be discarded by jq (in this case only)
list="$(echo; printf "%s" "${li[@]}";)"

# pass jq command
quoted_commands="$(jq -R 'reduce inputs as $line
        ([]; . + ["echo \($line) :; grep -rl \($line) \($dir); echo"])
        | (join("; "))' \
    --arg dir $dir <<< "$list")"
# the elements are read with reduce filter and converted to JSON Array of corresponding commands to execute
# the commands for all elements of list are joined with join filter

# trim quotes to execute commands properly
commands=$(sed -e 's/^"//' -e 's/"$//' <<< "$quoted_commands")

# run commands
eval "$commands"

You may want to print the above variables. Take care to use quotes in echo/printf while doing so, i.e., echo "$variable".

Replacement of sed command:

signgle_quoted=${quoted%\"}
commands=${signgle_quoted#\"}
echo "$commands"

I am now using the following implementations (though the dictionary implementation uses a for loop, the key : value implementation doesn't, and is a single line command):

# print an Associative bash array as a JSON dictionary
print_dict()
{
    declare -n ref
    ref=$1
    for k in $(echo "${!ref[@]}")
    do
        printf '{"name":"%s", "value":"%s"}\n' "$k" "${ref[$k]}"
    done | jq -s 'reduce .[] as $i ({}; .[$i.name] = $i.value)'
}

#-------------------------------------------------------------------------

# print the grep output in key : value format
function list_grep()
{
    local listfile=$1
    local dir=$2
    eval $(jq -Rsr 'split("\n") | map(select(length > 0)) | reduce .[] as $line ([]; . + ["echo \($line) :; grep -rl \($line) \($dir); echo"]) | (join("; "))' --arg dir "$dir" < "$listfile")
}

#-------------------------------------------------------------------------

# print the grep output as JSON dictionary
function dict_grep()
{
    local listfile=$1
    local dir=$2
    eval declare -A Arr=\($(eval echo $(jq -Rrs 'split("\n") | map(select(length > 0)) | reduce .[] as $k ([]; . + ["[\($k)]=\\\"$(grep -rl \($k) tmp)\\\""]) | (join(" "))' --arg dir $dir < tmp/list.txt))\)
    print_dict Arr
}

#-------------------------------------------------------------------------

# call:
list_grep $listfile $dir
dict_grep $listfile $dir

-Himanshu



Answered By - Himanshu Tanwar
Answer Checked By - Candace Johnson (WPSolving Volunteer)