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 ofgrep
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.
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}'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}')"
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)"
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 startNVO,
- anNVO,
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 GNUxargs
. Removing the two0
s from the example command would fix that, but leave you open to issues involving file names containing newlines. - The
-F
option, as shown, will makegrep
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 togrep
, 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
Elf Header or Installation Issue with Bcrypt in Docker Container
Xdp Program Ip Link Error: Prog Section Rejected: Operation Not Permitted
Command Not Found in Bash's If-Else Condition When Using [! -D "$Dir"]
Have One Folder with Files That Have the Same Name But Different File
Amazon Linux: "Apt-Get: Command Not Found"
Number of Processors/Cores in Command Line
Writing to Serial Port from Linux Command Line
How to Define a Bash Alias as a Sequence of Multiple Commands
How to Get the Architecture of a '.A' File
Linux - Threads and Process Scheduling Priorities
Delete a Column from a Delimited File in Linux
Using Bash Environment Variables from Within a Perl Script
Execute Command Line and Return Command Output
Add Blank Line Between Lines from Different Groups
Linux Command or Script Counting Duplicated Lines in a Text File
Recursively Find Files with a Specific Extension
Automating Amazon Ebs Snapshots Anyone Have a Good Script or Solution for This on Linux