Listing Running Processes and Sending Them to a File - bash

my function is supposed to list all running processes and store them to process.id and if process.id exists, it should rename it to the current date with .id at the end of it, and then move it to the /logs directory. i think i have the mv and rename part working but it doesnt seem to save all of the processes to the file. do i have a syntax error on that part?
function processsaver()
{
if [ -r "process.id" ]; then
mv "process.id" logs/$(date +%d-%m-%y).id
ps -e > /process.id
fi
}

process.id and /process.id are not the same path. You probably wanted process.id or ./process.id in both places, since this kind of information really should not be in the filesystem root.

Related

How to iterate between directories in shell script

I want to convert images from .img to .nii.gz using the function fslchfiletype.
These images are stored in Controls and Patients folders, each one of this folders have several folders belonging to each one of the individuals, like C01, C02, , etc. Specifically, each one of the individuals has the .img files inside a folder called rs_roi, which is inside another folder called ROIS2. This is what I have:
DIR="/media/Roy"; cd "$DIR/Analysis"
for group in Controls Patients; do
for case in $group; do
mkdir $DIR/Analysis/$group/$case/Cortical_masks
for file in $DIR/Analysis/$group/$case/ROIS2/rs_roi/.img; do
fslchfiletype NIFTI_GZ "$file"
done;
done;
done;
Notice how I also want to create a folder called Cortiical_maks inside each and one of the individuals.
This gives me the next error:
mkdir: cannot create directory ´media/Roy/Analysis/Controls/Controls/Cortical_masks´: No such file or directory.
Cannot open volume media/Roy/Analysis/Controls/Controls/ROIS2/rs_roi/ for reading!
mkdir: cannot create directory ´media/Roy/Analysis/Patients/Patients/Cortical_masks´: No such file or directory.
Cannot open volume media/Roy/Analysis/Patients/Patients/ROIS2/rs_roi/ for reading!
It´s iterating two times the Controls Patients folder: Control/Control. Maybe the problem is here for case in $group; do? Thx
Once you have your directory name assigned to a variable, you have to glob the directory to get its contents. Otherwise, as you saw, $group is not expanded, and you're only looping over that single term itself.
You might also like to check that each entry is indeed a directory before you traverse into it.
for case in $group/*; do
[ -d $case ] || continue
mkdir $DIR/Analysis/$group/$case/Cortical_masks
for file in $DIR/Analysis/$group/$case/ROIS2/rs_roi/.img; do
fslchfiletype NIFTI_GZ "$file"
done;
done;
You should probably also quote your variables in more places, unless you are sure they don't need quoting. I always lint my scripts with shellcheck to get that kind of advice.
I made a small change to #Noah answer, this script works fine:
for group in Controls Patients; do
for case in $group/*; do
[ -d $case ] || continue
mkdir $DIR/Analysis/$case/Cortical_masks
for file in $DIR/Analysis/$case/ROIS2/rs_roi/*.img; do
fslchfiletype NIFTI_GZ "$file"
done;
done;
done;
I deleted $group in both paths, and added * in *.img which i forgot.

How to recursively rename all files and folder including specific part of the filename with Windows Bash?

This has to be a duplicate but I have read and tried at least a dozen of Q&As here on SO, and I cannot get any of them working for my case.
Really hope this won't result in downvotes because of it.
So I'm on Windows (10) and have a Bash terminal that I want to use for my task. The MINGW64 one I downloaded when I started working with Git.
I would prefer the solution with this program, but will be perfectly happy with one in Command Prompt Terminal or even PowerShell.
I created a TemplateApp which is in C:\Apps\TemplateApp folder which has multiple folders and subfolders named TemplateApp or TemplateApp.something as well as a lot of files that have TemplateApp as a part of their name.
Could be:
TemplateApp.ext
TemplateApp.something.ext
something.TemplateApp.something.ext
Then I copied the uppermost folder to C:\Apps\TemplateApp - Copy and in turn renamed it to C:\Apps\ProductionApplication.
Now for the love of whomever, I cannot make any of the scripts I found on SO to work for my case, ie. to rename all the above mentioned files and folders by replacing TemplateApp with ProductionApplication.
Here is a bash function I wrote that I think does very much like what you are wanting to do.
function func_CreateSourceAndDestination() {
#
for (( i = 0 ; i < ${#files_syncSource[#]} ; i++ )) ; do
files_syncDestination[${i}]="${files_syncSource[${i}]#${directory_MusicLibraryRoot_source}}"
file_destinationPath="$( dirname -- "${directory_PMPRoot_destination}${files_syncDestination[${i}]}" )"
if [ ! -d "${file_destinationPath}" ] ; then
mkdir -p "${file_destinationPath}"
fi
rsync -rltDvPmz "${files_syncSource[${i}]}" "${directory_PMPRoot_destination}${files_syncDestination[${i}]}"
done
}
In my case I'm feeding into rsync for a source and a destination. I'm pulling all the file paths from an array that has been split into path segments. I have to make certain character substitutions for FAT and NTFS file systems. I do this recursively.
files_syncDestination[${i}]="${files_syncDestination[${i}]//\:/__}"
That's the magic. I load a new array with the character substituted. You could do the same with a loaded variable including your phrases for change.
files_syncDestination[${i}]="${files_syncDestination[${i}]//${targetPhrase}/${subPhrase}}"
After that change in the function, you could use rsync or cp or mv as you prefer to go from your source array to your destination array.
(The double-slash in the substitution makes the substitution global.)

Detecting that files are being copied in a folder

I am running a script which copies one folder from a specific location if it does not exist( or is not consistent). The problems appears when I run concurently the script 2+ times. As the first script is trying to copy the files, the second comes and tryes the same thing resulting in a mess. How could I avoid this situation? Something like system wide mutex.
I tryed a simple test with -w, I manually copied the folder and while the folder was copying I run the script:
use strict;
use warnings;
my $filename = 'd:\\folder_to_copy';
if (-w $filename) {
print "i can write to the file\n";
} else {
print "yikes, i can't write to the file!\n";
}
Of course this won't work, cuz I still have write acces to that folder.
Any ideea of how could I check if the folder is being copied in Perl or usingbatch commands?
Sounds like a job for a lock file. There are myriads of CPAN modules that implement lock files, but most of them don't work on Windows. Here are a few that seem to support Windows according to CPAN Testers:
File::Lockfile
File::TinyLock
File::Flock::Tiny
After having a quick view at the source code, the only module I can recommend is File::Flock::Tiny. The others seem racy.
If you need a systemwide mutex, then one "trick" is to (ab)use a directory. The command mkdir is usually atomic and either works or doesn't (if the directory already exists).
Change your script as follows:
my $mutex_dir = '/tmp/my-mutex-dir';
if ( mkdir $mutex_dir ) {
# run your copy-code here
# when finished:
rmdir $mutex_dir;
} else {
print "another instance is already running.\n";
}
The only thing you need to make sure is that you're allowed to create a directory in /tmp (or wherever).
Note that I intentionally do NOT firstly test for the existence of $mutex_dir because between the if (not -d $mutex_dir) and the mkdir someone else could create the directory and the mkdir would fail anyway. So simply call mkdir. If it worked then you can do your stuff. Don't forget to remove the $mutex_dir after you're done.
That's also the downside of this approach: If your copy-code crashes and the script prematurely dies then the directory isn't deleted. Presumably the lock file mechanism suggested in nwellnhof's answer behaves better in that case and automatically unlocks the file.
As the first script is trying to copy the files, the second comes and
tries the same thing resulting in a mess
A simplest approach would be to create a file which will contain 1 if another instance of script is running. Then you can add a conditional based on that.
{local $/; open my $fh, "<", 'flag' or die $!; $data = <$fh>};
die "another instance of script is running" if $data == 1;
Another approach would be to set an environment variable within the script and check it in BEGIN block.
You can use Windows-Mutex or Windows-Semaphore Objects of the package
http://search.cpan.org/~cjm/Win32-IPC-1.11/
use Win32::Mutex;
use Digest::MD5 qw (md5_hex);
my $mutex = Win32::Mutex->new(0, md5_hex $filename);
if ($mutex) {
do_your_job();
$mutex->release
} else {
#fail...
}

looping files with bash

I'm not very good in shell scripting and would like to ask you some question about looping of files big dataset: in my example I have alot of files with the common .pdb extension in the work dir. I need to loop all of them and i) to print name (w.o pdb extension) of each looped file and make some operation after this. E.g I need to make new dir for EACH file outside of the workdir with the name of each file and copy this file to that dir. Below you can see example of my code which are not worked- it's didn't show me the name of the file and didn't create folder for each of them. Please correct it and show me where I was wrong
#!/bin/bash
# set the work dir
receptors=./Receptors
for pdb in $receptors
do
filename=$(basename "$pdb")
echo "Processing of $filename file"
cd ..
mkdir ./docking_$filename
done
Many thanks for help,
Gleb
If all your files are contained within the .Repectors folder, you can loop each of them like so:
#!/bin/bash
for pdb in ./Receptors/*.pdb ; do
filename=$(basename "$pdb")
filenamenoextention=${filename/.pdb/}
mkdir "../docking_${filenamenoextention}"
done
Btw:
filenamenoextention=${filename/.pdb/}
Does a search replace in the variable $pdb. The syntax is ${myvariable/FOO/BAR}, and replaces all "FOO" substrings in $myvariable with "BAR". In your case it replaces ".pdb" with nothing, effectively removing it.
Alternatively, and safer (in case $filename contains multiple ".pdb"-substrings) is to remove the last four characters, like so: filenamenoextention=${filename:0:-4}
The syntax here is ${myvariable:s:e} where s and e correspond to numbers for the start and end index (not inclusive). It also let's you use negative numbers, which are offsets from the end. In other words: ${filename:0:-4} says: extract the substring from $filename starting from index 0, until you reach fourth-to-the-last character.
A few problems you have had with your script:
for pdb in ./Receptors loops only "./Receptors", and not each of the files within the folder.
When you change to parent directory (cd ..), you do so for the current shell session. This means that you keep going to the parent directory each time. Instead, you can specify the parent directory in the mkdir call. E.g mkdir ../thedir
You're looping over a one-item list, I think what you wanted to get is the list of the content of ./Receptors:
...
for pdb in $receptors/*
...
to list only file with .pdb extension use $receptors/*.pdb
So instead of just giving the path in for loop, give this:
for pdb in $receptors/*.pdb
To remove the extension :
set the variable ext to the extension you want to remove and using shell expansion operator "%" remove the extension from your filename eg:
ext=.pdb
filename=${filename%${ext}}
You can create the new directory without changing your current directory:
So to create a directory outside your current directory use the following command
mkdir ../docking_$filename
And to copy the file in the new directory use cp command
After correction
Your script should look like:
receptors=./Receptors
ext=.pdb
for pdb in $receptors/*.pdb
do
filename=$(basename "$pdb")
filename=${filename%${ext}}
echo "Processing of $filename file"
mkdir ../docking_$filename
cp $pdb ../docking_$filename
done

What does this bash script function does

I am new to shell scripting and i found this function in a given script file.
##############################
# rotate_daily(filename)
rotate_daily() {
_code=0
_file_src=$1
_today=`date '+%Y-%m-%d'`
_file_dest=${_file_src}.${_today}
if [ -f ${_file_dest} ]; then
printk "rotate_daily(): ${_file_dest} already exist"
_code=1
else
if [ -f ${_file_src} ]; then
printk "rotate_daily(): ${_file_src} => ${_file_dest}"
cp -p ${_file_src} ${_file_dest}
_code=$?
>${_file_src}
fi
fi
}
I understand this is kind of coping file from one location to another location. But, it is not rotating right?. could somebody explain me what it is really does.
thanks in advance for any help
It copies _file_src to the location file_dest unless _file_dest already exists. An informative message will be printed that tells you if the file already exists or file_src_ will be copied, It also moves _file_src only if it is a file.
EDIT: forgot to mention what the command >{_file_src} does - it simply wipes out the contents of the source file. So you will have the contents of _file_src moved to file_dest in the end and _file_src will be empty. I can't figure why not simply do a move(with mv) and then create an empty file, but that's your question.
If the time stamped file already exists, this code snippet does nothing but print a message via printk indicating that. If it does not exist, it copies the source file to it and truncates the source file. I would guess that the line you are not quite understanding is:
>${_file_src}
That line truncates the original file after it has been copied. Note that there is a race condition, and any data written to the file between the copy and the truncation will be lost.

Resources