3

I need to select files which contain "Error" or "traffic" in their names, e.g.

abc_ERRor.csv raError.csv bsn_Error.csv bbbctraffic.csv ccc_traffic.csv ... 

and move them into corresponding directories like Error_directory and traffic_directory according to their names.

I tried this but it didn't work

mv $(ls test_file | grep -l 'Error>' *) Error_directory 

How can I do this from the command-line?

ls test_file | grep 'Error' 
1
  • grep is irrelevant here. Start with the task, and then determine the tools, and try to avoid using Unix commands as verbs unless that is exactly what you mean. Commented Sep 14, 2012 at 18:48

5 Answers 5

6

Parsing the output of ls is rarely a good idea due to the wide range of characters that can occur in file names. A better solution might be:

find ./test_file -iname "*error*" -print0 | xargs -0 -I {} mv {} Error_directory 

Notice the -iname option. This will return case insensitive matches, allowing you to find and move files such as:

abc_ERRor.csv error_123.csv ErRoR_77.csv 

If you don't need your search to be case insensitive, something as simple as this should suffice:

mv test_file/*Error* Error_directory 

Further reading:

xargs separator problem

bash pitfalls

2
  • 1
    +1 for pointing out the error in attempting to use ls, but piping find directly to xargs isn't any safer. Use find -print0 | xargs -0 OR find ... -exec instead. Shell globs are usually the best way to go, if possible. Commented Sep 14, 2012 at 18:54
  • @jw013: Thanks, good spot. I added some resources for anyone interested in avoiding these problems. Commented Sep 14, 2012 at 19:28
1

Another possible solution is:

#!/bin/sh err_dir=~/errors tra_dir=~/traffic for f in *.csv; do case $f in *[Ee][Rr][Rr][Oo][Rr]*) mv -i $f $err_dir ;; *[Tt][Rr][Aa][Ff][Ii][Cc]*) mv -i $f $tra_dir ;; esac done 
3
  • You could get away with just sh since no bash-specific features were used or required in this snippet. Also, for future reference, case doesn't do word splitting so you don't need the double quotes around $f. Commented Sep 14, 2012 at 18:55
  • @jw013 Thanks for the reminder. Is there a way to use regular expression instead of globs in case statements? Commented Sep 14, 2012 at 19:00
  • 1
    POSIX sh doesn't do regex in case or anywhere else that I know of, and bash doesn't in case AFAIK. Usually globs are sufficient but if you require regex you might have to go with a fancier shell or find. In this particular case regular expressions are overkill. Commented Sep 14, 2012 at 19:03
0

You could use find:

find test_file -type f -name "*Error*" -exec mv {} Error_directory/ \;

where -type f denotes that you are looking for files, -name states that you are matching on the pattern given. exec runs the following command, with the {} taking the place of files that match the parameters given to find.

If you want to use bash and do something more along the lines of what you've tried, a loop should do the trick:

for f in `ls test_file | grep 'Error'; do mv test_file/${f} Error_directory done 

In both examples, I've assumed test_file is a directory containing the files you are interested in.

0
ls | grep Error | xargs -I % mv % error-dir 
0
for fn in *.*; do for word in Error traffic; do echo "$fn" | grep -i "$word" && mkdir -p "$word"_directory && mv "$fn" "$word"_directory; done; done 

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.