简体   繁体   中英

BASH one-line alphabetical mass file sort using for, mv, and grep

Problem

I've got thousands of files with the format "^[[:digit:]]\\{4\\} - [[:alpha:]].*" , for exampe: 7958 - a3ykof zyimeo3.txt. I'm trying to simply move them into folders alphabetically beginning with the first alpha-character after the hyphen.

I feel like I'm so close to getting this to happen the way I want but there's a (hopefully simple) problem.

I tested the commmand with echo first to make sure it grabs the correct information. Then I tried to execute it for real with mv. I've included some examples below based on this list of files:

1439 - a74389 josifj3oj.txt
3589 - Bfoei 839982 3il.txt
4719 - an38n8f n839mm20 mi02.txt
6398 - b39ji oij3o8 j2o.txt
9287 - A2984 j289jj9 oiw.txt
.... several thousand more files

Examples

This works

This lists all the files starting with the letter "a" (after the 4 digits-space-hyphen-space pattern in the beginning):

for i in "$(ls | grep -i "^[[:digit:]]\{4\} - a")"; do echo "$i"; done

This fails

This doesn't put all the files starting with the letter "a" (after the 4 digits-space-hyphen-space pattern) in the "A" folder:

for i in "$(ls | grep -i "^[[:digit:]]\{4\} - a")"; do mv "$i" A; done

I expected this second command to move each file named "#### - a*" or "#### - A*" to the folder named A. But it sees it as one big string/filename joined by "\\n".

Here's an example error message:

mv: cannot stat '1439 - a74389 josifj3oj.txt\n9287 - A2984 j289jj9 oiw.txt\n2719 - an38n8f n839mm20 mi02.txt': No such file or directory

Does anybody know what I'm missing?

Edit

Between @alvits's answer and @chepner's and @courtlandj comments, what worked flawless for me was this:

for directory in {A..Z}; do
    mkdir -p "$directory" &&
    find . -iregex "./[0-9]* - ${directory}.*" -exec mv -t "$directory" {} +; 
done

Here's the simplest way to do it.

for directory in {A..Z}; do
    mkdir "$directory" &&
    find . -iregex "./[0-9]* - ${directory}.*" -exec mv "{}" "$directory" \;
done

The for loop will query for filenames according to each directory they belong.

The find command will find the files and move them to the directory.

BASH has RE-like globbing, and sequence creation, built-in. You can make use of it something like this:

for i in {{A..Z},{a..z}}; do
  mkdir "${i}" && mv [0-9][0-9][0-9][0-9]" - ${i}"*" "${i}"
done

You notice the four repetitions of the digits, and yeah it looks clumsier than a normal RE like [0-9]{4} .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM