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.