Change working directory while looping over folders - linux

Currently I am trying to run MRI software (TBSS) on imaging files(scan.nii.gz) on the Linux command line.
The scans are all stored in separate folders for different participants and the file names are identical,so:
/home/scans/participant1/scan.nii.gz
/home/scans/participant2/scan.nii.gz
/home/scans/participant3/scan.nii.gz
What this software does is it creates the result of the analysis in the current working directory.Since the scans have the same image name, they get overwritten al the time.
I would like to loop through all the participant folders, make it my working directory and then execute the tbss command, which is simply tbss_1_preproc scan.nii.gz. In this way, the file will be stored in the current working directory,which is the participant directory.
Is there any sensible way of doing this in Linux ?
Thanks so much !

Try it in BASH. The code below is untested, but it should give you a clue
#! /bin/bash
find . -name scan.nii.gz | while read line
do
cd $(dirname "${line}")
tbss_1_preproc $(basename "${line}")
done
Put it in a file and make it executable. Copy it to your scans folder and execute it.

Related

cd command : how to go back an unknown number of levels from current subdirectory to a particular parent directory (unix and dos)

Ok, so I am trying to resolve a uri in an xmlcatalog and I want to go back from a particular sub-directory back to a parent-directory that is an-unknown-number-of-levels behind.
eg:
file:///D:/Sahil/WorkSpaces1/Cartridges1/Project1/ParticularFolder/Level1/Level2/<so-many-levels>/CurrentFolder
I want to go back from "CurrentFolder" to "ParticularFolder" without typing in the full FilePath.
I want to achieve this because, I work in multiple Projects which all have "ParticularFolder" in it, so the codes inside the sub-directories of this folder should dynamically have access to all other files in other sub-directories inside this parent folder. I do not want to specify separate full filepaths for my various projects and make the code too rigid.
Is it possible? Please mention how to achieve this in windows, unix as well as linux os.
In UNIX/Linux/OS X/etc.:
while [ "$(basename $PWD)" != "ParticularFolder" ]; do cd ..; done

Move files to different directories based on file name tokens

I am looking to write a script to move files from a directory:
/home/mydir/
To another directory based on tokens in the file name. I have a bunch of files named as such:
red_office_mike_2015_montreal_546968.ext
or
$color_$location_$name_$year_$city_$numbers.extension (files will be various movie files: mov, mp4, mkv, etc.)
I would like the script to move the files to the following location:
/dir/work/$color/$name
Then verify the file has successfully copied, and delete the original file once it has.
I would also love it if the script would create the to directory if it does not already exist.
So in summary, I need a script to move files based on underscore separated tokens, create the to directory if it doesn't already exist, verify the successful copy (maybe with a size check), then delete the original file.
I am working on linux, and would prefer a bash script. The variables I have given are generic, and I will incorporate some other things to the script, I'm just looking for help on building the skeleton.
Thanks in advance for any help!
It's not a bash script, but perl is much better at this kind of thing and is installed on all Linux systems
while(<>) {
chomp;
$file = $_;
($colour, $location, $name, $year, $city, $numbers) = split(/_/,$file);
$dest0 = "/dir/work/$colour";
$dest1 = "$dest0/$name";
mkdir ($dest0) unless (-d $dest0);
mkdir ($dest1) unless (-d $dest1);
rename ($file, "$dest1/$file");
}
The script splits your input file on the underscore character, creates all the directories to the destination and then renames the file to the new filename. Rename takes care of all the copying and deleting for you. In fact it just changes the directory entries without any copying at all.
UPDATE
The above version takes its input from a file containing a list of filenames to process. For an alternative version which processes all files in the current directory, replace the while line with
while(glob("*")) {
I was able to fumble around online and come up with a for loop to do this task. I used cut and it made things simple. Here is what worked for me:
#!/bin/sh
cd "${1:-.}"
for f in *.*; do
color=`echo "$f" | cut -d'_' -f1`
name=`echo "$f" | cut -d'_' -f3`
todir="/dir/work/$color/$name"
mkdir -p "$todir"
mv "$f" "$todir"
done
This worked perfectly and I hope it can help others who might need to create directories based on portions of filenames.
The first line under the shebang made it so that it will either look at the current working directory or a directory you pass it as an argument.
Thanks to those who chimed in on the original post. I'm new with scripting so it take me a while to figure this stuff out. I love this site though, it is super helpful!

How to use command zip in linux that folder have short path?

I used command zip in linux (RedHat), this is my command:
zip -r /home/username/folder/compress/zip.zip /home/username/folder/compressed/*
Then, i open file zip.zip, i see architecture as path folder compress.
I want to in folder zip only consist list file *.txt
Because i used this command in script crontab hence i can't use command cd to path folder before run command zip
Please help me
I skimmed the zip man page and this is what I have found. There is not an option archive files relative to a different directory. The closest I have found is zip -j which removes the entire path and stores the files directly in the zip rather than sub directories. I do not know what happens in the case of file name conflicts such as if /home/username/folder/compressed/a.txt and /home/username/folder/compressed/subdir/a.txt both exist. If this is not a problem for you, you can use this option, but I am concerned because you did specify the -r option indicating that you expect zip to traverse sub folders.
I also thought of the possibility that your script could somehow call zip with a different working directory, but I took a look at this unix stack exchange page and it looks like their options use cd.
I have to admit I do not understand why you cannot use cd and I am very curious about it. You said something about using crontab, but I have never heard of anything wrong with changing directories in a crontab script.
I used option -j in command zip
zip -jr /home/username/folder/compress/zip.zip /home/username/folder/compressed/*
and i was yet settled this problem, thanks

how to copy between folders and parent folder without complete path

This is a basic question but I am struggling to find a decent solution. This is hindering my script from automation.
I have the following path.
/home/hassan/Dyna/ProjectSimulation
in project simulation I have 3 folders
friction time force
like
/home/hassan/Dyna/ProjectSimulation/friction
Now I have a file friction1.txt in this friction folder and I want to copy it to ProjectSimulation.
is it possible to avoid complete path and just one step down?
Also if I have to copy this friction1.txt to folder force, is there anyway to avoid the complete path.
I mean I have a subroutine but this is path dependent , whenever I run it , I have to run in the same folder and then copy my results so I can run only one instance of my simulation.
Experts please guide me.
PS: This is part of a 600 lines shell.
This comes across as so basic that I must have misunderstood something in your question.
If you want to refer to a parent directory, .. is the way to do that. So, if you want to copy friction1.txt to two places you just do
cp friction1.txt ..
cp friction1.txt ../force
All you need to take care of is making sure that CWD is
/home/hassan/Dyna/ProjectSimulation/friction
so that the references point at the right place.
You can temprarily change the current directory to ProjectSimulation, copy the file (cp friction/friction1.txt .), then change the path back to the original (so the rest of the script works as before)
Alternatively, you can use dirname to get he name of the parent directory and use that.
Change to the root dir of your known directory structure. Then do the copy operations with relative paths. Then change back to your dir where you came from.
Your friends are:
cd
cd -
or better:
pushd
popd
(see man bash)
I.e.
pushd /home/hassan/Dyna/ProjectSimulation
cp friction/friction1.txt .
cp friction/friction1.txt force
popd

linux server create symbolic links from filenames

I need to write a shell script to run as a cron task, or preferably on creation of a file in a certain folder.
I have an incoming and an outgoing folder (they will be used to log mail). There will be files created with codes as follows...
bmo-001-012-dfd-11 for outgoing and 012-dfd-003-11 for incoming. I need to filter the project/client code (012-dfd) and then place it in a folder in the specific project folder.
Project folders are located in /projects and follow the format 012-dfd. I need to create symbolic links inside the incoming or outgoing folders of the projects, that leads to the correct file in the general incoming and outgoing folders.
/incoming/012-dfd-003-11.pdf -> /projects/012-dfd/incoming/012-dfd-003-11.pdf
/outgoing/bmo-001-012-dfd-11.pdf -> /projects/012-dfd/outgoing/bmo-001-012-dfd-11.pdf
So my questions
How would I make my script run when a file is added to either incoming or outgoing folder
Additionally, is there any associated disadvantages with running upon file modification compared with running as cron task every 5 mins
How would I get the filename of recent (since script last run) files
How would I extract the code from the filename
How would I use the code to create a symlink in the desired folder
EDIT: What I ended up doing...
while inotifywait outgoing; do find -L . -type l -delete; ls outgoing | php -R '
if(
preg_match("/^\w{3}-\d{3}-(\d{3}-\w{3})-\d{2}(.+)$/", $argn, $m)
&& $m[1] && (file_exists("projects/$m[1]/outgoing/$argn") != TRUE)
){
`ln -s $(pwd)/outgoing/$argn projects/$m[1]/outgoing/$argn;`;
}
'; done;
This works quite well - cleaning up deleted symlinks also (with find -L . -type l -delete) but I would prefer to do it without the overhead of calling php. I just don't know bash well enough yet.
Some near-answers for your task breakdown:
On linux, use inotify, possibly through one of its command-line tools, or script language bindings.
See above
Assuming the project name can be extracted thinking positionally from your examples (meaning not only does the project name follows a strict 7-character format, but what precedes it in the outgoing file also does):
echo `basename /incoming/012-dfd-003-11.pdf` | cut -c 1-7
012-dfd
echo `basename /outgoing/bmo-001-012-dfd-11.pdf`| cut -c 9-15
012-dfd
mkdir -p /projects/$i/incoming/ creates directory /projects/012-dfd/incoming/ if i = 012-dfd,
ln -s /incoming/foo /projects/$i/incoming/foo creates a symbolic link from the latter argument, to the preexisting, former file /incoming/foo.
How would I make my script run when a file is added to either incoming or outgoing folder
Additionally, is there any associated disadvantages with running upon file modification compared with running as cron task
every 5 mins
If a 5 minutes delay isn't an issue, I would go for the cron job (it's easier and -IMHO- more flexible)
How would I get the filename of recent (since script last run) files
If your script runs every 5 minutes, then you can tell that all the files created in between now (and now - 5 minutes) are newso, using the command ls or find you can list those files.
How would I extract the code from the filename
You can use the sed command
How would I use the code to create a symlink in the desired folder
Once you have the desired file names, you can usen ln -s command to create the symbolic link

Resources