Execute function for every subfolder - linux

I have a folder named students_projects that contains 10 subfolders. Each subfolder has project1.c and project2.c, each one prints a value. I made a bash script function that check those numbers and save them to a txt file. I tested it with 2 .c files named project1 and project2 in Desktop and not in the folder. I made sure that i worked fine but when i went to run it for all the subfolders it keeps saving the values that are in desktop files.
My function:
function test () {
gcc project1.c
p1=$(./a.out)
if (( $p1 == 20 ));
then
v1=30
else
v1=0
fi
gcc project2.c
p2=$(./a.out)
if (($p2 == 10 ));
then
v2=70
else
v2=0
fi
sum=$(( $v1 + $v2 ))
on="cut -d' ' -f1 report.txt"
onoma=$(eval "$on")
temp="cut -d' ' -f2 report.txt"
am=$(eval "$temp")
printf "$onoma $am project1: $v1 project2: $v2 total_grade: $sum\n" >> grades.txt
}
Then i do
for FILE in students_projects/* ; do
test
done

Looks like the grades.txt file is at the top level, but you want to run test under each directory. The easiest change is to pass a full path to $PWD/grades.txt to the function. Coombine that with running "cd" into each subdir. Recommendation:
for FILE in students_projects/* ; do
(cd $FILE; test $PWD/grades.txt)
done
Then in your "function test()", use that $1 argument instead of grades.txt:
printf "..." >> $1

Related

Create a file named with a specific pattern

Need some help here. I need to create an executable file for every user that exists on the system ( Linux ) and the format for file is the following :
fis_nr_username
where nr stands for 1st file, 2nd file etc...
EXAMPLE OF SITUATION
Users on machine :
stud01
stud02
stud03
I need a file for each of them to be executable and look like this :
file_1_stud01
file_2_stud02
file_3_stud03
You could loop through the user list, then loop through file number (here 0 to 10). Use printf with %03d to pad with zeros.
#!/usr/bin/env bash
username="stud01 stud02 stud03"
for name in $username; do
for ((i=0; i<11; i++)); do
printf "file_%03d_%s\n" $i $name
done
done
You could make this a function and put it in .bashrc
newfiles() {
username="$#"
for name in $username; do
for ((i=0; i<3; i++)); do
printf "file_%03d_%s\n" $i $name
done
done
}
call the function from terminal with: newfiles firstuser serconduser. Output:
fis_000_firstuser
fis_001_firstuser
fis_002_firstuser
fis_000_seconduser
fis_001_seconduser
fis_002_seconduser

bash: How to transfer/copy only the file names to separate similar files?

I've some files in a folder A which are named like that:
001_file.xyz
002_file.xyz
003_file.xyz
in a separate folder B I've files like this:
001_FILE_somerandomtext.zyx
002_FILE_somerandomtext.zyx
003_FILE_somerandomtext.zyx
Now I want to rename, if possible, with just a command line in the bash all the files in folder B with the file names in folder A. The file extension must stay different.
There is exactly the same amount of files in each folder A and B and they both have the same order due to numbering.
I'm a total noob, but I hope some easy answer for the problem will show up.
Thanks in advance!
ZVLKX
*Example edited for clarification
An implementation might look a bit like this:
renameFromDir() {
useNamesFromDir=$1
forFilesFromDir=$2
for f in "$forFilesFromDir"/*; do
# Put original extension in $f_ext
f_ext=${f##*.}
# Put number in $f_num
f_num=${f##*/}; f_num=${f_num%%_*}
# look for a file in directory B with same number
set -- "$useNamesFromDir"/"${f_num}"_*.*
[[ $1 && -e $1 ]] || {
echo "Could not find file number $f_num in $dirB" >&2
continue
}
(( $# > 1 )) && {
# there's more than one file with the same number; write an error
echo "Found more than one file with number $f_num in $dirB" >&2
printf ' - %q\n' "$#" >&2
continue
}
# extract the parts of our destination filename we want to keep
destName=${1##*/} # remove everything up to the last /
destName=${destName%.*} # and past the last .
# write the command we would run to stdout
printf '%q ' mv "$f" "$forFilesFromDir/$destName.$f_ext"; printf '\n'
## or uncomment this to actually run the command
# mv "$f" "$forFilesFromDir/$destName.$f_ext"
done
}
Now, how would we test this?
mkdir -p A B
touch A/00{1,2,3}_file.xyz B/00{1,2,3}_FILE_somerandomtext.zyx
renameFromDir A B
Given that, the output is:
mv B/001_FILE_somerandomtext.zyx B/001_file.zyx
mv B/002_FILE_somerandomtext.zyx B/002_file.zyx
mv B/003_FILE_somerandomtext.zyx B/003_file.zyx
Sorry if this isn't helpful, but I had fun writing it.
This renames items in folder B to the names in folder A, preserving the extension of B.
A_DIR="./A"
A_FILE_EXT=".xyz"
B_DIR="./B"
B_FILE_EXT=".zyx"
FILES_IN_A=`find $A_DIR -type f -name *$A_FILE_EXT`
FILES_IN_B=`find $B_DIR -type f -name *$B_FILE_EXT`
for A_FILE in $FILES_IN_A
do
A_BASE_FILE=`basename $A_FILE`
A_FILE_NUMBER=(${A_BASE_FILE//_/ })
A_FILE_WITHOUT_EXTENSION=(${A_BASE_FILE//./ })
for B_FILE in $FILES_IN_B
do
B_BASE_FILE=`basename $B_FILE`
B_FILE_NUMBER=(${B_BASE_FILE//_/ })
if [ ${A_FILE_NUMBER[0]} == ${B_FILE_NUMBER[0]} ]; then
mv $B_FILE $B_DIR/$A_FILE_WITHOUT_EXTENSION$B_FILE_EXT
break
fi
done
done

Using bash script to update number in a php script file [duplicate]

This question already has answers here:
How to increment version number in a shell script?
(14 answers)
Closed 8 years ago.
I use the following bash/shell script to semi-automate the git add/commit/push routine on my project:
git_push.sh
#!/bin/bash
# Mini Config
RColor='\e[0m'
Red='\e[0;31m';
Green='\e[0;32m';
Yellow='\e[0;33m'
# Change To Working Directory
clear;
cd $HOME/public_html/iwms_reboot;
# Get Git Commit Notes
echo -en "\r\n${Green}Enter commit notes: ${Yellow}";
read notes;
if [[ -z "$notes" ]]
then
echo -e "\r\n${Red}ERROR: You have not entered any git commit notes.${RColor}\r\n";
exit 0;
fi
echo -e "${RColor}";
# Git Add, Commit & Push
git add .;
git commit -m "${notes}";
echo -e "\r\n";
git push;
echo -e "\r\n";
This works perfectly fine.
I want to take this one step further. On my prject, there is a single file called version.php with the following lines of code:
<?php
// Script Version
$script_version = 'v1.0.5';
?>
My question is, is it possible to use bash/shell scripting to load this file's content and find the number after the 2nd period (.) and increment it by one?
i.e. v1.0.5 will become v1.0.6
This way, I can run this version number updating function before my (git add/commit/push) routine to implement an automatic minor version number update functionality on my project. I.e. script version number goes up automatically every time I commit.
If you want a 'pure-bash' solution, here it is...:
#!/bin/bash
new_version=''
increment_version_number () {
declare -a part=( ${1//\./ } )
declare new
declare -i carry=1
for (( CNTR=${#part[#]}-1; CNTR>=0; CNTR-=1 )); do
len=${#part[CNTR]}
new=$((part[CNTR]+carry))
[ ${#new} -gt $len ] && carry=1 || carry=0
[ $CNTR -gt 0 ] && part[CNTR]=${new: -len} || part[CNTR]=${new}
done
new="${part[*]}"
new_version="${new// /.}";
}
version=$(sed version.php -e "s/\$script_version = 'v//" | sed -e "s/';$//")
increment_version_number $version
echo $new_version;
UPDATE:
Code for a two digits version numbers (as requested in comment):
#!/bin/bash
new_version=''
increment_version_number () {
declare -a part=( ${1//\./ } )
declare new
declare -i carry=1
for (( CNTR=${#part[#]}-1; CNTR>=0; CNTR-=1 )); do
len=${#part[CNTR]}
new=$((part[CNTR]+carry))
[ ${#new} -gt $(($len+1)) ] && carry=1 || carry=0
part[CNTR]=${new}
done
new="${part[*]}"
new_version="${new// /.}";
}
version=$(grep "\$script_version" version.php | sed -e "s/\$script_version = 'v//" | sed -e "s/';$//")
increment_version_number $version
echo $new_version;
(warning: not fully tested code...)
Thanks to fredtantini and using the answer from How to increment version number in a shell script?, I have come up with the following solution to my original problem.
I first created a file called version.data and put the text 1.0.5 in it.
Then I updated my PHP script like so:
<?php
// Script Version
$script_version = 'v'. trim(file_get_contents(app_path() .'/version.data'));
?>
Then I have created the following gawk script called version_updater.sh (next to my git_push.sh script):
#!/usr/bin/gawk -f
BEGIN {
printf("%s", inc(ARGV[1]))
}
function inc(s, a, len1, len2, len3, head, tail)
{
split(s, a, ".")
len1 = length(a)
if(len1==0)
return -1
else if(len1==1)
return s+1
len2 = length(a[len1])
len3 = length(a[len1]+1)
head = join(a, 1, len1-1)
tail = sprintf("%0*d", len2, (a[len1]+1)%(10^len2))
if(len2==len3)
return head "." tail
else
return inc(head) "." tail
}
function join(a, x, y, s)
{
for(i=x; i<y; i++)
s = s a[i] "."
return s a[y]
}
Then I have updated my git_push.sh script like so:
#!/bin/bash
# Mini Config
RColor='\e[0m'
Red='\e[0;31m';
Green='\e[0;32m';
Yellow='\e[0;33m';
Source=$HOME/public_html/iwms_reboot;
# Increment Script Version
CurrentVersion=`cat "$Source/app/version.data"`;
NewVersion=`./version_updater.sh $CurrentVersion`;
# Change To Working Directory
clear;
cd $Source;
# Get Git Commit Notes
echo -en "\r\n${Green}Enter commit notes: ${Yellow}";
read notes;
if [[ -z "$notes" ]]
then
echo -e "\r\n${Red}ERROR: You have not entered any git commit notes.${RColor}\r\n";
exit 0;
fi
echo -e "${RColor}";
# Update Script Version
echo $NewVersion > $Source/app/version.data;
# Git Add, Commit & Push
git add .;
git commit -m "${notes}";
echo -e "\r\n";
git push;
echo -e "\r\n";
... and that's it, it works.
when the script runs, it reads the current version, passes it to the version_updater.sh to programatically increment it and put the return value into a variable.
Just before I commit, I update my version.data file with the updated version number. Now when I commit, I commit with the new version number.

Try to change files name in bash

I'm trying my first program in BASH
The program needs to change the files name in directory.
The first argument is base name and the second argument is a file extension
If I call to the function with:
rename Test jpg
then the resulting files should have names like:
Test001.jpg, Test002.jpg, Test003.jpg,...
What I tried:
function rename {
index=0
for i in $1"/"*".$2"; do
newName=$(printf $1/"$1%04d."$2 ${index})
mv $i $newName
let index=index+1
done
}
And when I call to the function
bash rename.sh pwd jpg
And nothing dosen't happened,please help me:)
What I would do :
rn(){
for i in $1*.$2; do
((index++))
newName=$(printf "$1%04d.$2" $index)
mv $i $newName
done
}
cd WHERE/YOU/WANT
rn "$#"

How to rename multiple files in terminal (LINUX)?

I have bunch of files with no pattern in their name at all in a directory. all I know is that they are all Jpg files. How do I rename them, so that they will have some sort of sequence in their name.
I know in Windows all you do is select all the files and rename them all to a same name and Windows OS automatically adds sequence numbers to compensate for the same file name.
I want to be able to do that in Linux Fedora but I you can only do that in Terminal. Please, help. I am lost.
What is the command for doing this?
The best way to do this is to run a loop in the terminal going from picture to picture and renaming them with a number that gets bigger by one with every loop.
You can do this with:
n=1
for i in *.jpg; do
p=$(printf "%04d.jpg" ${n})
mv ${i} ${p}
let n=n+1
done
Just enter it into the terminal line by line.
If you want to put a custom name in front of the numbers, you can put it before the percent sign in the third line.
If you want to change the number of digits in the names' number, just replace the '4' in the third line (don't change the '0', though).
I will assume that:
There are no spaces or other weird control characters in the file names
All of the files in a given directory are jpeg files
That in mind, to rename all of the files to 1.jpg, 2.jpg, and so on:
N=1
for a in ./* ; do
mv $a ${N}.jpg
N=$(( $N + 1 ))
done
If there are spaces in the file names:
find . -type f | awk 'BEGIN{N=1}
{print "mv \"" $0 "\" " N ".jpg"
N++}' | sh
Should be able to rename them.
The point being, Linux/UNIX does have a lot of tools which can automate a task like this, but they have a bit of a learning curve to them
Create a script containing:
#!/bin/sh
filePrefix="$1"
sequence=1
for file in $(ls -tr *.jpg) ; do
renamedFile="$filePrefix$sequence.jpg"
echo $renamedFile
currentFile="$(echo $file)"
echo "renaming \"$currentFile\" to $renamedFile"
mv "$currentFile" "$renamedFile"
sequence=$(($sequence+1))
done
exit 0
If you named the script, say, RenameSequentially then you could issue the command:
./RenameSequentially Images-
This would rename all *.jpg files in the directory to Image-1.jpg, Image-2.jpg, etc... in order of oldest to newest... tested in OS X command shell.
I wrote a perl script a long time ago to do pretty much what you want:
#
# reseq.pl renames files to a new named sequence of filesnames
#
# Usage: reseq.pl newname [-n seq] [-p pad] fileglob
#
use strict;
my $newname = $ARGV[0];
my $seqstr = "01";
my $seq = 1;
my $pad = 2;
shift #ARGV;
if ($ARGV[0] eq "-n") {
$seqstr = $ARGV[1];
$seq = int $seqstr;
shift #ARGV;
shift #ARGV;
}
if ($ARGV[0] eq "-p") {
$pad = $ARGV[1];
shift #ARGV;
shift #ARGV;
}
my $filename;
my $suffix;
for (#ARGV) {
$filename = sprintf("${newname}_%0${pad}d", $seq);
if (($suffix) = m/.*\.(.*)/) {
$filename = "$filename.$suffix";
}
print "$_ -> $filename\n";
rename ($_, $filename);
$seq++;
}
You specify a common prefix for the files, a beginning sequence number and a padding factor.
For exmaple:
# reseq.pl abc 1 2 *.jpg
Will rename all matching files to abc_01.jpg, abc_02.jpg, abc_03.jpg...

Resources