0

I have many files (with a .fna extension). I need to move them, if they contain the character > a certain number of times.

I know which files contain > a certain number of times (9 times in this example) with this command.

grep -c ">" *.fna | grep ":9" 

Which gives an output like this

5242_ref.fna:9 9418_ref.fna:9 

But I don't know how to move those files to another folder.

Thanks.

4
  • If a line contains two symbols (>>), does it count only once (as grep -c would do), or twice (as "contains > a certain number of times" would do? Commented Apr 2, 2020 at 20:03
  • counts as twice Commented Apr 2, 2020 at 20:22
  • I've updated my answer accordingly. You might update your Q to remove the misleading "grep" output as what you intend is different -- grep counts matching lines, not matching bytes. Commented Apr 2, 2020 at 20:27
  • Relating only (for the grep occurrence vs line background): unix.stackexchange.com/q/398413/117549 Commented Apr 2, 2020 at 20:27

2 Answers 2

2

By combining egrep (called with the -l option so that positive matches return only filenames) with xargs you can perform arbitrary commands based on text matches:

[gnubeard@mothership: ~/mver]$ ls destination example.fna non_example.fna [gnubeard@mothership: ~/mver]$ cat example.fna >>>>>>>>> [gnubeard@mothership: ~/mver]$ cat non_example.fna <<<<<<<<< >> [gnubeard@mothership: ~/mver]$ egrep -l '>{9}' *.fna | xargs -I{} mv {} destination/ [gnubeard@mothership: ~/mver]$ ls destination non_example.fna [gnubeard@mothership: ~/mver]$ ls destination/ example.fna 

Edit: This doesn't match files with a certain number of instances of a character, if they're separated by other characters or newlines. I've created this short script that should operate as desired.

#! /usr/bin/env bash DESTINATION=./destination MATCH_CHAR='>' MATCH_COUNT=9 for FILE in $1; do MATCHES=$(grep -o $MATCH_CHAR $FILE | wc -l) if [ $MATCHES -eq $MATCH_COUNT ]; then mv $FILE $DESTINATION fi done 

Example:

[gnubeard@mothership: ~/mver]$ ls destination example.fna mver non_example.fna [gnubeard@mothership: ~/mver]$ cat example.fna >> >>foo>>bar>>>baz [gnubeard@mothership: ~/mver]$ cat non_example.fna <<<<<<<<< >> [gnubeard@mothership: ~/mver]$ ./mver *.fna [gnubeard@mothership: ~/mver]$ ls destination/ example.fna [gnubeard@mothership: ~/mver]$ ls destination mver non_example.fna 
3
  • liked the egrep solution. however, as it is it searchs for >>>>>>>>> and I need to move files with > 9 times not necessarily grouped, but anywhere in the file. what can I do? Commented Apr 2, 2020 at 20:20
  • 1
    This does answer the question as stated. However there is the bug that @JeffSchaller found. Time for another question. Commented Apr 2, 2020 at 20:26
  • I've updated with a solution that'll work regardless of separating characters/newlines. Commented Apr 2, 2020 at 20:52
1

You could use zsh with its expression-as-a-glob-qualifier to select files that only have nine such symbols:

$ hasnine() { [[ $(tr -dc '>' < "$REPLY" | wc -c) -eq 9 ]]; } $ mv *.fna(+hasnine) location/ 

The first line defines a function whose purpose is to create a true/false filter for files that have nine > symbols in them. The tr command acts on its input, expected in the REPLY variable, deleting anything that is not a >, then asks wc to count the number of resulting characters, and then compares that output to 9.

The second line executes the mv command for matching *.fna files to the (example) location directory. Matching *.fna files also have to pass the expression qualifier, which is given as the name of the function we defined.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.