move all the folders and files to the folder with the same subject name in the directory Linux - linux

I have for example 001, 001_ses-1, 001_ses-2 folders and files 001_lg1.lsf, 001_recon1.lsf, 001_trac1.lsf in the same directory. I have hundreds of subjects.
I want to move folders: 001_ses-1, 001_ses-2, and files: 001_lg1.lsf , recon1_001.lsf and trac1_001.lsf to 001 main folder. How do I do this?
list={001, 011, 023, 059, ..... 102}
for i in list; do rm i* i; done
so far, I have no clues. Need some help figuring it out!

Given the information provided in the comments, there are two possibilities for identifying the destination folders:
A) Create a manual list. This is how it is done in Bash and compatible Linux shells:
DEST_LIST=( "001" "002" "003" "004" )
for DEST in ${DEST_LIST[#]}; do
mv "${DEST}_"* "${DEST}"
B) Create a regular expression of the pattern and use find.
I will use the pattern from your comment as an example:
PREFIX_PATTERN="[0-9]\{3\}_S_[0-9]\{3\}\.[0-9]"
for DEST in $(find . -type d -regex ".*/${PREFIX_PATTERN}"); do
PREFIX=`expr "${DEST}" : ".*\(${PREFIX_PATTERN}\)"`
mv "${PREFIX}_"* "${DEST}"
The extra line containing the expr command extracts the clean folder name from the full folder path returned by find command.

Related

How to rename all the files from a directory?

So, i have a given directory, and that directory contains other subdirectories, and every subdirectory can contain a file. I have to change all the files names, so that it will end in ".txt" .
**You can do something like this using bash : and go over all your directories with it **
for f in *.their_current_end;
do
mv -- "$f" "${f%.their_current_end}.txt"
done
another solution would be using : rename in Linux
rename [OPTIONS] perlexpr files
where the rename will rename all the files mentioned like the regex supplied in the perlexpr parameter.
example :
rename 's/.html/.php/' \*.html

How to remove all files except the ones that matches a pattern along several number of directories

lets say I have a my_dirs/ directory, insdie that directory I have several parallel subdirectories which has several files and I want to delete all of them except the ones that have the substring '.regions'
this is my parent directory content:
this is what I tried:
shopt -s extglob
rm -r !(./**/*.regions*)
but I got an error message: cannot be deleted «! (./**/*. region *) »: The file or directory does not exist.
how can I do that?
First of all, always be careful when deleting multiple files.
The command to achieve what you want would be:
find my_dirs -type f ! -name "*.regions*" -delete
"-delete" must be last, otherwise it will delete everything it finds
This will explore all subdirectories in my_dirs, find the files (-type f) that not (!) contain ".regions" ("*.regions*") on their name, and delete (-delete) them.
I recommend running this first: find my_dirs -type f ! -name "*.regions*",
so it won't delete anything and you can check the files are correct.
Edit: Added -type f so it only targets files per Philippe's suggestion.

renaming particular files in the subfolders with full directory path

experts, i have many folders and inside the folder there are many sub-folders and the sub-folders contain many files.However, in all the sub-folders one file name is same that is input.ps.Now i want to rename the same input.ps with full path plus file name
so input.ps in all directories should be renamed to home_wuan_data_filess_input.ps
i tried
#!/bin/sh
for file in /home/wuan/data/filess/*.ps
do
mv $file $file_
done
But it does not do the same as i expect,i hope experts will help me.Thanks in advance.
so input.ps in all directories should be renamed to home_wuan_data_filess_input.ps
You may use this find solution:
find /home/wuan/data/filess -type f -name 'input*.ps' -exec bash -c '
for f; do fn="${f#/}"; echo mv "$f" "${fn//\//_}"; done' _ {} +
while read line;
do
fil=${line//\//_}; # Converts all / characters to _ to form the file name
fil=${fil:1}; # Remove the first -
dir=${line%/*}; # Extract the directory
echo "mv $line $dir/$fil"; # Echo the move command
# mv "$line" "$dir/$fil"; # Remove the comment to perform the actual command
done <<< "$(find /path/to/dir -name "input.ps")"
Ok, so file will end up being
/home/wuan/data/filess/input.ps
What we need here is the path, and the full, snake-cased name. Let's start by getting the path:
for f in /home/wuan/data/filess/*.ps; do
path="${f%*/}";
This will match the substring of f up until the last occurrence of /, effectively giving us the path.
Next, we want to snake_case all the things, which is even easier:
for f in /home/wuan/data/filess/*.ps; do
path="${f%*/}";
newname="${f//\//_}"
This replaces all instances of / with _, giving the name you want the new file to have. Now let's put all of this together, and move the file f to path/newname:
for f in /home/wuan/data/filess/*.ps; do
path="${f%*/}";
newname="${f//\//_}"
mv "${f}" "${path}/${newname}"
done
That should do the trick
Here's one of many sites listing some of the bash string manipulations you can use.
Sorry for the delayed update, the power in my building just cut out :)

How to match partly matching filenames from two directories and execute commands on what found

I'm trying to match two directories and if the file exists in the second directory, I want to move files from the first directory to a third one.
The filenames do not matching exactly, they get a "_ica" at the end of the name and a different extension.
I have tried to write a script that loops through dir1 checks if it's in dir2
and if found move to dir3:
DATA= /home/eegfilesonlyWM/*
PROCESSED= /home/eegfilesonlyWM/icaddata/*
DONE= /home/eegfilesonlyWM/done/
for f in $DATA ; do
fname=${f##*/}
fname=${fname%/}
find /home/eegfilesonlyWM/icaddata/ -iname "${fname*_ica*}" -type f -exec mv {} ./done \;
done
I would like to copy from the first directory those files that already have corresponding files in the second directory.
Thank you for any help
Maybe this will do what you want:
#!/usr/bin/env bash
#Directory paths here
DATA=./DATA
PROCESSED=./PROCESSED
DONE=./DONE
#Do the test and copy here
for f in `ls -1 $DATA`; do
#build output name
p="$PROCESSED/${f/\.xxx/}"; #xxx is the file extension of original
p="${p}_ica.yyy"; #yyy is the file extension of the processed
if [ -f $p ] ; then
cp $DATA/$f $DONE
fi
done

Recursive find that will append directory name to any file

Any help would be greatly appreciated!
I need a way to append the parent directory name to any file in any path.
An example current directory tree
/Hawaii/Surfing/800x600/picture1.jpg
/Hawaii/Surfing/800x600/picture2.jpg
/Hawaii/Surfing/800x600/picture3.jpg
/RockClimbing/SouthAfrica/TableMountain/4096x2160/Picture1.jpg
/RockClimbing/SouthAfrica/TableMountain/4096x2160/Picture2.jpg
/RockClimbing/SouthAfrica/TableMountain/4096x2160/Picture3.jpg
The goal
/Hawaii/Surfing/800x600/picture1.800x600.jpg
/Hawaii/Surfing/800x600/picture2.800x600.jpg
/Hawaii/Surfing/800x600/picture3.800x600.jpg
/RockClimbing/SouthAfrica/TableMountain/4096x2160/Picture1.4096x2160.jpg
/RockClimbing/SouthAfrica/TableMountain/4096x2160/Picture2.4096x2160.jpg
/RockClimbing/SouthAfrica/TableMountain/4096x2160/Picture3.4096x2160.jpg
I have found some examples of this but the users all have set directory depths unfortunately I have files at many different levels.
find dir -name *.jpg -exec rename -nv -- 's|/(.*)/(.*)$|/$1/$1.jpg|' {}
Your first capture group is matching everything before the last /, not just the last directory name. Use /([^/]*)/ instead of /(.*)/ so it won't match across / delimiters. You're also not splitting up the filename into the name and extension, so you're not inserting the directory name between them.
find dir -name *.jpg -exec rename -nv -- 's|([^/]*)/([^/]*)\.jpg$|$1/$2.$1.jpg|' {} +

Resources