Search code examples
linuxbashshellmv

Moving files with a pattern in their name to a folder with the same pattern as its name


My directory contains mix of hundreds of files and directories similar to this:

508471/
ae_lstm__ts_ 508471_detected_anomalies.pdf
ae_lstm__508471_prediction_result.pdf
mlp_508471_prediction_result.pdf
mlp__ts_508471_detected_anomalies.pdf
vanilla_lstm_508471_prediction_result.pdf
vanilla_lstm_ts_508471_detected_anomalies.pdf

598690/
ae_lstm__ts_598690_detected_anomalies.pdf
ae_lstm__598690_prediction_result.pdf
mlp_598690_prediction_result.pdf
mlp__ts_598690_detected_anomalies.pdf
vanilla_lstm_598690_prediction_result.pdf
vanilla_lstm_ts_598690_detected_anomalies.pdf

There are folders with an ID number as their names, like 508471 and 598690.
In the same path as these folders, there are pdf files that have this ID number as part of their name. I need to move all the pdf files with the same ID in their name, to their related directories.

I tried the following shell script but it doesn't do anything. What am I doing wrong?
I'm trying to loop over all the directories, find the files that have id in their name, and move them to the same dir:

for f in ls -d */; do
    id=${f%?}  # f value is '598690/', I'm removing the last character, `\`, to get only the id part 
    find . -maxdepth 1 -type f -iname *.pdf -exec grep $id {} \; -exec mv -i {} $f \;
done

Solution

  • #!/bin/sh
    find . -mindepth 1 -maxdepth 1 -type d -exec sh -c '
        for d in "$@"; do
            id=${d#./}
            for file in *"$id"*.pdf; do
                [ -f "$file" ] && mv -- "$file" "$d"
            done
        done
    ' findshell {} +
    

    This finds every directory inside the current one (finding, for example, ./598690). Then, it removes ./ from the relative path and selects each file that contains the resulting id (598690), moving it to the corresponding directory.

    If you are unsure of what this will do, put an echo between && and mv, it will list the mv actions the script would make.

    And remember, do not parse ls.