Combine File Modified Date and "Grep" Results Through "Find", in One Line

Combine file modified date and grep results through find , in one line

You can use this find+grep combination to get the formatted result:

while IFS=$'\06' read -r -d '' t f; do
sed "s/^/$t /" <(grep -HTni 'σχόλια' "$f")
done < <(find . -type f -mmin -10 -not \( -path ./admin -prune \) \
-not \( -path ./people/languages -prune \) \
-not \( -path ./include -prune \) \
-printf '%TY-%Tm-%Td %Ta %TH:%TM:%.2TS\06%p\0')
  • Note use of \06 as field delimiter to address filenames/paths with whitespaces/newlines etc.
  • \0 (NULL) is used as line terminator for the same reason.
  • %.2TS is used to trip fractional part of the second value.
  • sed is used to insert date/time at line start of grep output.

PHP Code:

$cmd = <<<'EOF'
export TZ=":Europe/Athens"; \
find . -type f -mmin -10 -not \( -path ./admin -prune \) \
-not \( -path ./people/languages -prune \) \
-not \( -path ./include -prune \) \
-printf '%TY-%Tm-%Td %Ta %TH:%TM:%.2TS\06%p\0' |
while IFS=$'\06' read -r -d '' t f; do grep -HTni 'σχόλια' "$f" | sed "s/^/$t /"; done
EOF;

// var_dump( $cmd );

echo shell_exec($cmd) . "\n";

How to combine results of grep command


grep 1000 /tmp/userfile | cut -d, -f2- | tr '\n' ',' | sed 's/,$//'

alternatively (in fact, better), as devnull suggests:

grep 1000 /tmp/userfile | cut -d, -f2- | paste -sd,

Merge the output of two greps into one file

You can easily combine both commands in a row, like:

grep 'substring1' file1.txt > outfile.txt ; grep 'substring2' file2.txt >> outfile.txt

The ";" separate both commands, the second command will be executed after the first has finished.

The ">>" means you append the output to the already existing file. (if the file does not exists, there will be no difference to ">")

You can use this simple pattern for many different tasks.

Combine output of two grep results without spaces in between

Let's simplify it one step at a time.

  1. The outer echo `...` can go. Backticks and echo are basically inverse operations and they (more or less) cancel out when combined.

    echo -n "$(grep "version=" file | awk -F= '{print $2 "."}')"
    grep -n "subversion=" file | awk -F= '{print $2}'
  2. An easier way to combine the two lines is to embed them inside a single printout.

    echo "$(grep "version=" file | awk -F= '{print $2}').$(grep "subversion=" file | awk -F= '{print $2}')"
  3. Awk can both search and print. No need for grep.

    echo "$(awk -F= '$1=="version" {print $2}' file).$(awk -F= '$1=="subversion" {print $2}' file)"
  4. You could make this easier to read by using printf to split it across multiple lines:

    printf '%s.%s\n' \
    "$(awk -F= '$1=="version" {print $2}' file)" \
    "$(awk -F= '$1=="subversion" {print $2}' file)"

That looks pretty good. But you know what? This screams for a one-pass solution. Awk is a pretty capable mini-language in its own right. We could have it save all the key/value pairs into a map and then print the results at the end:

awk -F= '{map[$1]=$2} END {print map["version"] "." map["subversion"]}' file

Here {map[$1]=$2} is executed for each line of the input file, saving the keys and values to a map. When the file is finished the END block runs and prints the two desired fields with a . in between.

Grep inside all files created within date range

This is a little different from Banthar's solution, but it will work with versions of find that don't support -newermt and it shows how to use the xargs command, which is a very useful tool.

You can use the find command to locate files "of a certain age". This will find all files modified between 5 and 10 days ago:

 find /directory -type f -mtime -10 -mtime +5

To then search those files for a string:

 find /directory -type f -mtime -10 -mtime +5 -print0 |
xargs -0 grep -l expression

You can also use the -exec switch, but I find xargs more readable (and it will often perform better, too, but possibly not in this case).

(Note that the -0 flag is there to let this command operate on files with embedded spaces, such as this is my filename.)

Update for question in comments

When you provide multiple expressions to find, they are ANDed together. E.g., if you ask for:

find . -name foo -size +10k

...find will only return files that are both (a) named foo and (b) larger than 10 kbytes. Similarly, if you specify:

find . -mtime -10 -mtime +5

...find will only return files that are (a) newer than 10 days ago and (b) older than 5 days ago.

For example, on my system it is currently:

$ date
Fri Aug 19 12:55:21 EDT 2016

I have the following files:

$ ls -l
total 0
-rw-rw-r--. 1 lars lars 0 Aug 15 00:00 file1
-rw-rw-r--. 1 lars lars 0 Aug 10 00:00 file2
-rw-rw-r--. 1 lars lars 0 Aug 5 00:00 file3

If I ask for "files modified more than 5 days ago (-mtime +5) I get:

$ find . -mtime +5
./file3
./file2

But if I ask for "files modified more than 5 days ago but less than 10 days ago" (-mtime +5 -mtime -10), I get:

$ find . -mtime +5 -mtime -10
./file2

How do you grep and save 2 different results into one file without them overwriting each other?

Simplest is to run the two commands in a subshell and collect the output of the subshell:

(grep 'SEE INTERVIEW #47246024' streets/Hart_Place; \
grep 'SEE INTERVIEW #699607' streets/Buckingham_Place ) > interviews.txt

Combine multiple grep variables in one column-wise file

In this answers the variable names are shortened to ini and align.

First, we extract the sample name and count from grep's output. Since we have to do this multiple times, we define the function

e() { sed -E 's,^.*/(.*)_R1.*:(.*)$,\1\t\2,'; }

Then we join the extracted data into one file. Lines with the same sample name will be combined.

join -t $'\t' <(e <<< "$ini") <(e <<< "$align")

Now we nearly have the expected output. We only have to add the header and draw lines for the table.

join ... | column -to " | " -N Sample,ini,align

This will print

Sample                                  | ini   | align
V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT | 13175 | 12589
V3_F357_N_V4_R805_1_A2_bach2_GAGTGATCGT | 14801 | 13934
V3_F357_N_V4_R805_1_A3_bach3_TGAGCGTGCT | 13475 | 12981
V3_F357_N_V4_R805_1_A4_bach4_TGTGTGCATG | 13424 | 12896
V3_F357_N_V4_R805_1_A5_bach5_TGTGCTCGCA | 12053 | 11617

Adding a horizontal line after the header is left as an exercise for the reader :)

This approach also works with more than two number columns. The join and -N parts have to be extended. join can only work with two files, requiring us to use an unwieldy workaround ...

e() { sed -E 's,^.*/(.*)_R1.*:(.*)$,\1\t\2,'; }
join -t $'\t' <(e <<< "$var1") <(e <<< "$var2") |
join -t $'\t' - <(e <<< "$var3") | ... | join -t $'\t' - <(e <<< "$varN") |
column -to " | " -N Sample,Col1,Col2,...,ColN

... so it would be easier to add another helper function

e() { sed -E 's,^.*/(.*)_R1.*:(.*)$,\1\t\2,'; }
j2() { join -t $'\t' <(e <<< "$1") <(e <<< "$2"); }
j() { join -t $'\t' - <(e <<< "$1"); }
j2 "$var1" "$var2" | j "$var3" | ... | j "$varN" |
column -to " | " -N Sample,Col1,Col2,...,ColN

Alternatively, if all inputs contain the same samples in the same order, join can be replaced with one single paste command.

Combine two grep commands to process input from a file or grep lines starting with one specific substring and contain another after

The operation you're attempting does not actually require combining two grep calls. Therefore, you can use

grep "^NVO,.*,B," file > outfile

Details:

  • ^ - string start
  • NVO, - an NVO, string
  • .* - any text (any zero or more chars)
  • ,B, - a ,B, text.

See the online demo:

#!/bin/bash
s='NVO,0,267,61,247357,247357,O,19:00:00.000000,06:09:08.417320,07:55:22.068670
DVD,0,267,61,247357,247357,O,19:00:00.000000,06:09:08.417320,07:55:22.068670
NVO,0,267,61,247358,247358,B,19:00:00.000000,06:09:08.417407,07:55:22.079291
DVD,0,267,61,247358,247358,B,19:00:00.000000,06:09:08.417407,07:55:22.079291'
grep "^NVO,.*,B," <<< "$s"

Output:

NVO,0,267,61,247358,247358,B,19:00:00.000000,06:09:08.417407,07:55:22.079291

How to display modified date time with 'find' command?

You could use the -exec switch for find and define the output format of stat using the -c switch as follows:

find /var -maxdepth 2 -type d -exec stat -c "%n %y" {} \;

This should give the filename followed by its modification time on the same line of the output.

Find files containing string among recently modified files in linux

Your other answers so far all suggest using find's -exec feature to run a grep command for each candidate file identified. That's viable, but launching hundreds or thousands of separate grep commands would be costly. It would be more efficient to combine find with xargs to reduce the number of separate grep commands to a minimum:

find / -type f -mtime -2 -print0 |
xargs -r0 grep -Fnw 'search string'

xargs will group the file names read from its standard input to form argument lists for grep commands starting with the given words, yielding a huge reduction in the number of separate grep commands.

Note also that:

  • The example command uses extensions provided by GNU find and GNU xargs. Removing the two 0s from the example command would fix that, but leave you open to issues involving file names containing newlines.
  • The -F option, as shown, will make grep slightly more efficient for the case you describe, where the search term is a fixed string. It will also protect you against the possibility of the search term being misinterpreted in the event that it contains any regex metacharacters.
  • find can use all sorts of additional information to be more selective about which files are passed on to grep, if you can glean any such details. For example, if you can determine what user will own the file, or anything about its mode (permissions), or a lower or upper bound on the file size. Also, if you can limit the search to less than the whole filesystem then of course that will improve the elapsed time, too.
  • For a large filesystem, it will take a fairly long time, no matter what you do, just to traverse all the files, even without reading any of their contents.


Related Topics



Leave a reply



Submit