4

I have a folder with many files like:

20_1_A.xml,
20_2_A.xml,
20_3_A.xml,
...

10_1_A.xml,
10_2_A.xml,
10_3_A.xml,
...

20_1_A.csv,
20_2_A.csv,
20_3_A.csv,
...

10_1_A.csv,
10_1_A.csv,
10_3_A.csv,
...

I want to group the files by the first number in the name using shell commands. For example:

  • all files starting with 20 inside a folder called 20 and all files starting with 10 in a folder called 10. The type of file doesn't matter.

Does anybody know how to to this? I thought of using wildcards but I don't know how…

3

Wildcards are the right tool. You could move all files like this:

for i in {10,20} # or something like $(seq 10 10 90) instead of {10,20} if you have a lot of different prefixes
do
    mkdir -p "$i" &&
      mv "$i"* "$i"/
done

You want mkdir -p so that mkdir doesn't complain if the target directory already exists.

|improve this answer|||||
  • Note that for i in {10,20} is the same (though less portable) as for i in 10 20. – Stéphane Chazelas Mar 10 '17 at 14:04
3
for datei in *_*.xml *_*.csv; 
 do mkdir -p -- "${datei%%_*}" && 
    mv -- "$datei" "${datei%%_*}"
 done

For each file matching the patterns create a dir named by the part before the first underscore (if it doesn't already exist, -p option) and move the file there.

Hope this fits.

|improve this answer|||||
2

With zsh:

mkdir_and_move() {mkdir -p -- $2:h && mv -- "$@"}
autoload zmv

zmv -P mkdir_and_move '(<->)*.(csv|xml)(#q.)' '$1/$f'

<-> is a glob that matches any decimal integer (<x-y> is integers from x to y). (#q.) is a glob qualifier that selects only regular files.

Similar to what you would be doing with a loop except that zmv adds a few sanity checks.

|improve this answer|||||
  • One more reason to like zsh! – Philippos Mar 10 '17 at 14:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.