0

My directory contains a list of .idat file pairs ending with either _Grn or _Red.

For each pair, I want to create a directory named after the substring before the first _ delimiter and move the files into their respective directories.

If the directories don't exist, create them before moving the files.

My code:

for file in *.idat; 
do directory_name=${file%_*} \ 
mkdir directory_name \ 
if ${file%_*}==directory_name; 
then 
mv $file directory_name;
fi; 
done

Traceback:

-bash: syntax error near unexpected token `then'

Filenames:

00f3408c-5ad1-4afb-9eac-3392aa92e42c_noid_Grn.idat 
00f3408c-5ad1-4afb-9eac-3392aa92e42c_noid_Red.idat 

0317b249-9256-47fe-9533-3ca91c07e3fd_noid_Grn.idat 
0317b249-9256-47fe-9533-3ca91c07e3fd_noid_Red.idat

039f8688-b4cd-4931-a8f5-40bcb1fbd8f0_noid_Grn.idat  
039f8688-b4cd-4931-a8f5-40bcb1fbd8f0_noid_Red.idat

Expected folder names:

00f3408c-5ad1-4afb-9eac-3392aa92e42c
0317b249-9256-47fe-9533-3ca91c07e3fd
039f8688-b4cd-4931-a8f5-40bcb1fbd8f0

1 Answer 1

2

Should be something like:

shopt -s nullglob extglob # dotglob
for file in [^_]*_@(Grn|Red).idat; do
  dirname=${file%%_*}
  mkdir -p -- "$dirname" &&
    mv -- "$file" "$dirname"
done

(uncomment the dotglob if you also want to consider hidden ones).

\ at the end of the line is a line continuation. It's use to break long lines to improve legibility.

do directory_name=${file%_*} \ 
mkdir directory_name \ 
if ${file%_*}==directory_name

is the same as

do directory_name=${file%_*} mkdir directory_name if ${file%_*}==directory_name

So it would ask mkdir to create directories called directory_name, if, 00f3408c-5ad1-4afb-9eac-3392aa92e42c_noid==directory_name with directory_name=00f3408c-5ad1-4afb-9eac-3392aa92e42c_noid passed in its environment.

Then the shell complains about that then without a corresponding if.

To do pattern matching in bash, you use the case construct or the [[ text = pattern ]] operator, but you don't need to here.

Also remember that expansions in list contexts must be quoted in bash, and the non-option arguments must be separated from options with -- for most commands.

${var%pattern} removes the shortest string that matches the pattern from the end of $var. You need ${var%%pattern} that removes the longest string for it to remove all from the first _. You'll notice that we use [^_]*... as the glob pattern to make sure the files don't start with a _ which would result in an empty directory name.

If you know there's always a Grn file for each Red file, you can reduce the number of invocations of mkdir and mv by half by doing:

shopt -s nullglob # dotglob
for file in [^_]*_Red.idat; do
  dirname=${file%%_*}
  mkdir -p -- "$dirname" &&
    mv -- "$file" "${file%_*}_Grn.idat" "$dirname"
done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .