Skip to main content
added 58 characters in body
Source Link
Kusalananda
  • 355.8k
  • 42
  • 735
  • 1.1k

Assuming that ./*.txt matches all the files that you are interested in, and that you want to find the files that contains all of the strings in the file ./patterns (may contain more than two lines):

#!/bin/bash

pathnames=( ./*.txt )

while IFS= read -r pattern; do
    for pathname in "${pathnames[@]}"; do
        pathnames=( ${pathnames[@]:1} )

        if grep -qF -e "$pattern" "$pathname"; then
            pathnames+=( "$pathname" )
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "${pathnames[@]}"

This loops over the patterns. For each pattern, it tests it against all files in the array pathnames. If the pattern matches, we keep the current pathname in the array, otherwise it's thrown away. At the end, pathnames will contain only the pathnames that contain all patterns.

Because of the way the pathnames array is managed, the number of grep calls made for each pattern will decrease as more and more files are discarded.

The command pathnames=( ${pathnames[@]:1} ) will shift off the first (current) pathname off from the array, while pathnames+=( "$pathname" ) puts it back in again at the end.

The command grep -qF -e "$pattern" "$pathname" will return a true value if the file $pathname contains the string in $pattern. We use -q to make grep quiet and also to make it exit as soon as it matches the pattern in the file. We use -F to do string comparisons rather than regular expression matches.


Only because I like the terser sh syntax more than named arrays in bash, here's a variation of the above for /bin/sh (the positional parameters replaces the pathnames array):

#!/bin/sh

set -- ./*.txt

while IFS= read -r pattern; do
    for pathname do
        shift

        if grep -qF -e "$pattern" "$pathname"; then
            set -- "$@" "$pathname"
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "$@"

Assuming that ./*.txt matches all the files that you are interested in, and that you want to find the files that contains all of the strings in the file ./patterns:

#!/bin/bash

pathnames=( ./*.txt )

while IFS= read -r pattern; do
    for pathname in "${pathnames[@]}"; do
        pathnames=( ${pathnames[@]:1} )

        if grep -qF -e "$pattern" "$pathname"; then
            pathnames+=( "$pathname" )
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "${pathnames[@]}"

This loops over the patterns. For each pattern, it tests it against all files in the array pathnames. If the pattern matches, we keep the current pathname in the array, otherwise it's thrown away. At the end, pathnames will contain only the pathnames that contain all patterns.

Because of the way the pathnames array is managed, the number of grep calls made for each pattern will decrease as more and more files are discarded.

The command pathnames=( ${pathnames[@]:1} ) will shift off the first (current) pathname off from the array, while pathnames+=( "$pathname" ) puts it back in again at the end.

The command grep -qF -e "$pattern" "$pathname" will return a true value if the file $pathname contains the string in $pattern. We use -q to make grep quiet and also to make it exit as soon as it matches the pattern in the file. We use -F to do string comparisons rather than regular expression matches.


Only because I like the terser sh syntax more than named arrays in bash, here's a variation of the above for /bin/sh (the positional parameters replaces the pathnames array):

#!/bin/sh

set -- ./*.txt

while IFS= read -r pattern; do
    for pathname do
        shift

        if grep -qF -e "$pattern" "$pathname"; then
            set -- "$@" "$pathname"
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "$@"

Assuming that ./*.txt matches all the files that you are interested in, and that you want to find the files that contains all of the strings in the file ./patterns (may contain more than two lines):

#!/bin/bash

pathnames=( ./*.txt )

while IFS= read -r pattern; do
    for pathname in "${pathnames[@]}"; do
        pathnames=( ${pathnames[@]:1} )

        if grep -qF -e "$pattern" "$pathname"; then
            pathnames+=( "$pathname" )
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "${pathnames[@]}"

This loops over the patterns. For each pattern, it tests it against all files in the array pathnames. If the pattern matches, we keep the current pathname in the array, otherwise it's thrown away. At the end, pathnames will contain only the pathnames that contain all patterns.

Because of the way the pathnames array is managed, the number of grep calls made for each pattern will decrease as more and more files are discarded.

The command pathnames=( ${pathnames[@]:1} ) will shift off the first (current) pathname off from the array, while pathnames+=( "$pathname" ) puts it back in again at the end.

The command grep -qF -e "$pattern" "$pathname" will return a true value if the file $pathname contains the string in $pattern. We use -q to make grep quiet and also to make it exit as soon as it matches the pattern in the file. We use -F to do string comparisons rather than regular expression matches.


Only because I like the terser sh syntax more than named arrays in bash, here's a variation of the above for /bin/sh (the positional parameters replaces the pathnames array):

#!/bin/sh

set -- ./*.txt

while IFS= read -r pattern; do
    for pathname do
        shift

        if grep -qF -e "$pattern" "$pathname"; then
            set -- "$@" "$pathname"
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "$@"
added 58 characters in body
Source Link
Kusalananda
  • 355.8k
  • 42
  • 735
  • 1.1k

Assuming that ./*.txt matches all the files that you are interested in, and that you want to find the files that contains all of the strings in the file ./patterns:

#!/bin/bash

pathnames=( ./*.txt )

while IFS= read -r pattern; do
    for pathname in "${pathnames[@]}"; do
        pathnames=( ${pathnames[@]:1} )

        if grep -qF -e "$pattern" "$pathname"; then
            pathnames+=( "$pathname" )
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "${pathnames[@]}"

This loops over the patterns. For each pattern, it tests it against all files in the array pathnames. If the pattern matches, we keep the current pathname in the array, otherwise it's thrown away. At the end, pathnames will contain only the pathnames that contain all patterns.

Because of the way the pathnames array is managed, the number of grep calls made for each pattern will decrease as more and more files are discarded.

The command pathnames=( ${pathnames[@]:1} ) will shift off the first (current) pathname off from the array, while pathnames+=( "$pathname" ) puts it back in again at the end.

The command grep -qF -e "$pattern" "$pathname" will return a true value if the file $pathname contains the string in $pattern. We use -q to make grep quiet and also to make it exit as soon as it matches the pattern in the file. We use -F to do string comparisons rather than regular expression matches.


Only because I like the terser sh syntax more than named arrays in bash, here's a variation of the above for /bin/sh (the positional parameters replaces the pathnames array):

#!/bin/sh

set -- ./*.txt

while IFS= read -r pattern; do
    for pathname do
        shift

        if grep -qF -e "$pattern" "$pathname"; then
            set -- "$@" "$pathname"
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "$@"

Assuming that ./*.txt matches all the files that you are interested in, and that you want to find the files that contains all of the strings in the file ./patterns:

#!/bin/bash

pathnames=( ./*.txt )

while IFS= read -r pattern; do
    for pathname in "${pathnames[@]}"; do
        pathnames=( ${pathnames[@]:1} )

        if grep -qF -e "$pattern" "$pathname"; then
            pathnames+=( "$pathname" )
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "${pathnames[@]}"

This loops over the patterns. For each pattern, it tests it against all files in the array pathnames. If the pattern matches, we keep the current pathname in the array, otherwise it's thrown away. At the end, pathnames will contain only the pathnames that contain all patterns.

Because of the way the pathnames array is managed, the number of grep calls made for each pattern will decrease as more and more files are discarded.

The command pathnames=( ${pathnames[@]:1} ) will shift off the first (current) pathname off from the array, while pathnames+=( "$pathname" ) puts it back in again at the end.

The command grep -qF -e "$pattern" "$pathname" will return a true value if the file $pathname contains the string in $pattern. We use -q to make grep quiet and also to make it exit as soon as it matches the pattern in the file. We use -F to do string comparisons rather than regular expression matches.


Only because I like the terser sh syntax more than named arrays in bash, here's a variation of the above for /bin/sh:

#!/bin/sh

set -- ./*.txt

while IFS= read -r pattern; do
    for pathname do
        shift

        if grep -qF -e "$pattern" "$pathname"; then
            set -- "$@" "$pathname"
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "$@"

Assuming that ./*.txt matches all the files that you are interested in, and that you want to find the files that contains all of the strings in the file ./patterns:

#!/bin/bash

pathnames=( ./*.txt )

while IFS= read -r pattern; do
    for pathname in "${pathnames[@]}"; do
        pathnames=( ${pathnames[@]:1} )

        if grep -qF -e "$pattern" "$pathname"; then
            pathnames+=( "$pathname" )
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "${pathnames[@]}"

This loops over the patterns. For each pattern, it tests it against all files in the array pathnames. If the pattern matches, we keep the current pathname in the array, otherwise it's thrown away. At the end, pathnames will contain only the pathnames that contain all patterns.

Because of the way the pathnames array is managed, the number of grep calls made for each pattern will decrease as more and more files are discarded.

The command pathnames=( ${pathnames[@]:1} ) will shift off the first (current) pathname off from the array, while pathnames+=( "$pathname" ) puts it back in again at the end.

The command grep -qF -e "$pattern" "$pathname" will return a true value if the file $pathname contains the string in $pattern. We use -q to make grep quiet and also to make it exit as soon as it matches the pattern in the file. We use -F to do string comparisons rather than regular expression matches.


Only because I like the terser sh syntax more than named arrays in bash, here's a variation of the above for /bin/sh (the positional parameters replaces the pathnames array):

#!/bin/sh

set -- ./*.txt

while IFS= read -r pattern; do
    for pathname do
        shift

        if grep -qF -e "$pattern" "$pathname"; then
            set -- "$@" "$pathname"
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "$@"
added 69 characters in body
Source Link
Kusalananda
  • 355.8k
  • 42
  • 735
  • 1.1k

Assuming that ./*.txt matches all the files that you are interested in, and that you want to find the files that contains all of the strings in the file ./patterns:

#!/bin/bash

pathnames=( ./*.txt )

while IFS= read -r pattern; do
    for pathname in "${pathnames[@]}"; do
        pathnames=( ${pathnames[@]:1} )

        if grep -qF -e "$pattern" "$pathname"; then
            pathnames+=( "$pathname" )
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "${pathnames[@]}"

This loops over the patterns. For each pattern, it tests it against all files in the array pathnames. If the pattern matches, we keep the current pathname in the array, otherwise it's thrown away. At the end, pathnames will contain only the pathnames that contain all patterns.

Because of the way the pathnames array is managed, the number of grep calls made for each pattern will decrease as more and more files are discarded.

The command pathnames=( ${pathnames[@]:1} ) will shift off the first (current) pathname off from the array, while pathnames+=( "$pathname" ) puts it back in again at the end.

The command grep -qF -e "$pattern" "$pathname" will return a true value if the file $pathname contains the string in $pattern. We use -q to make grep quiet and also to make it exit as soon as it matches the pattern in the file. We use -F to do string comparisons rather than regular expression matches.


Only because I like the terser sh syntax more than named arrays in bash, here's a variation of the above for /bin/sh:

#!/bin/sh

set -- ./*.txt

while IFS= read -r pattern; do
    for pathname do
        shift

        if grep -qF -e "$pattern" "$pathname"; then
            set -- "$@" "$pathname"
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "$@"

Assuming that ./*.txt matches all the files that you are interested in, and that you want to find the files that contains all of the strings in the file ./patterns:

#!/bin/bash

pathnames=( ./*.txt )

while IFS= read -r pattern; do
    for pathname in "${pathnames[@]}"; do
        pathnames=( ${pathnames[@]:1} )

        if grep -qF -e "$pattern" "$pathname"; then
            pathnames+=( "$pathname" )
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "${pathnames[@]}"

This loops over the patterns. For each pattern, it tests it against all files in the array pathnames. If the pattern matches, we keep the current pathname in the array, otherwise it's thrown away. At the end, pathnames will contain only the pathnames that contain all patterns.

Because of the way the pathnames array is managed, the number of grep calls made for each pattern will decrease as more and more files are discarded.

The command pathnames=( ${pathnames[@]:1} ) will shift off the first (current) pathname off from the array.

The command grep -qF -e "$pattern" "$pathname" will return a true value if the file $pathname contains the string in $pattern. We use -q to make grep quiet and also to make it exit as soon as it matches the pattern in the file. We use -F to do string comparisons rather than regular expression matches.

Assuming that ./*.txt matches all the files that you are interested in, and that you want to find the files that contains all of the strings in the file ./patterns:

#!/bin/bash

pathnames=( ./*.txt )

while IFS= read -r pattern; do
    for pathname in "${pathnames[@]}"; do
        pathnames=( ${pathnames[@]:1} )

        if grep -qF -e "$pattern" "$pathname"; then
            pathnames+=( "$pathname" )
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "${pathnames[@]}"

This loops over the patterns. For each pattern, it tests it against all files in the array pathnames. If the pattern matches, we keep the current pathname in the array, otherwise it's thrown away. At the end, pathnames will contain only the pathnames that contain all patterns.

Because of the way the pathnames array is managed, the number of grep calls made for each pattern will decrease as more and more files are discarded.

The command pathnames=( ${pathnames[@]:1} ) will shift off the first (current) pathname off from the array, while pathnames+=( "$pathname" ) puts it back in again at the end.

The command grep -qF -e "$pattern" "$pathname" will return a true value if the file $pathname contains the string in $pattern. We use -q to make grep quiet and also to make it exit as soon as it matches the pattern in the file. We use -F to do string comparisons rather than regular expression matches.


Only because I like the terser sh syntax more than named arrays in bash, here's a variation of the above for /bin/sh:

#!/bin/sh

set -- ./*.txt

while IFS= read -r pattern; do
    for pathname do
        shift

        if grep -qF -e "$pattern" "$pathname"; then
            set -- "$@" "$pathname"
        fi
    done
done < ./patterns

printf 'Matched: %s\n' "$@"
Source Link
Kusalananda
  • 355.8k
  • 42
  • 735
  • 1.1k
Loading