Linking directories inside directories in Bash - regex

My script processes files.lst and it has a loop that looks like this
while read src_column dest_column; do
if [[ -d $src ]]; then
src="../../default/$src_column/*"
else
src="../../default/$src_column"
fi
pushd $dest
ln -s $src .
popd
done < files.lst
files.lst
#~source~ ~destination~
data dir1
default/def1.txt new1.txt
data dir2/dir22/dir222
default/def1.txt dir2/dir22/dir222/new1.txt
default dir2/dir22
default/def2.txt dir2/dir22/ne2.txt
The cases should be like this:
if destinations are dir2/dir22/dir222 or dir2/dir22/dir222/new1.txt
the starting prefix of $src should be ../../../../default
if destinations are dir2/dir22 or dir2/dir22/new2.txt
the starting prefix of $src should be ../../../default
if destinations are dir2 or dir2/new2.txt
the starting prefix of $src should be ../../default
The problem is I don't know how I will count the directories how deep they are. What approach should I do? I am thinking of regex but I got no idea how I'll use it.

Using sed to calculate the paths...:
while read src_column dest_column; do
if [[ -d $src ]]; then
dest_column="$dest_column/"
fi
src_prefix="$(sed -r 's|/[^/]*$|/|; s|//*|/|g; s|[^/]+|..|g' <<< "./$dest_column")default"
# sed command details:
# First expression: strip out any file.txt from $dest_column
# 2nd expression: Change duplicate / to single / (e.g. a/b//c// to a/b/c
# Last expression: Change any path to `..`
#Finally append the missing ../default.
if [[ -d $src ]]; then
src="$src_prefix/$src_column/*"
else
src="$src_prefix/$src_column"
fi
pushd $dest
ln -s $src .
popd
done < files.lst

Related

`cd` into a directory using a pattern

I am trying to cd into a directory which is named with an ip address(eg: 10.0.10.10). The name of the folder changes as the ip address of the node changes. I want to have dynamic cd command to cd into that folder. cd ~/mnt/<ip address pattern>
It works if I use cd ~/mnt/1* or any other similar wildcard operator is used. I want it to be worked with the pattern [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}
If your find supports -regex (you may want to add -regextype with GNU find systems or -E on BSD find to enable ERE syntax):
re='(^|/)[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
IFS= read -r -d '' dirname < <(find /mnt -maxdepth 1 -type d -regex "$re" -print0)
[[ $dirname ]] && cd "$dirname"
...or you can just use native bash:
re='(^|/)[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
for dir in /mnt/*; do
[[ $dir =~ $re ]] && { cd "$dir" && break; }
done

Renaming directories based on a pattern in Bash

I have a Bash script that works well for just renaming directories that match a criteria.
for name in *\[*\]\ -\ *; do
if [[ -d "$name" ]] && [[ ! -e "${name#* - }" ]]; then
mv "$name" "${name#* - }"
fi
done
Currently if the directory looks like:
user1 [files.sentfrom.com] - Directory-Subject
It renames the directory and only the directory to look like
Directory-Subject (this could have different type of text)
How can I change the script / search criteria to now search for
www.ibm.com - Directory-Subject
and rename the directory and only the directory to
Directory-Subject
You could write your code this way so that it covers both the cases:
for dir in *\ -\ *; do
[[ -d "$dir" ]] || continue # skip if not a directory
sub="${dir#* - }"
if [[ ! -e "$sub" ]]; then
mv "$dir" "$sub"
fi
done
Before running the script:
$ ls -1d */
user1 [files.sentfrom.com] - Directory-Subject/
www.ibm.com - Directory-Subject
After:
$ ls -1d */
Directory-Subject/
www.ibm.com - Directory-Subject/ # didn't move because directory existed already
A simple answer would be to change *\[*\]\ -\ * to *\ -\ *
for name in *\ -\ *; do
if [[ -d "$name" ]] && [[ ! -e "${name#* - }" ]]; then
mv "$name" "${name#* - }"
fi
done
For more information, please read glob and wildcards

Shell script to rename multiple files from their parent folders

I'm looking for a script for below structure:
Before :
/Description/TestCVin/OpenCVin/NameCv/.....
/Description/blacVin/baka/NameCv_hubala/......
/Description/CVintere/oldCvimg/NameCv_add/.....
after:
/Description/TestaplCVin/OpenaplCVin/NameaplCv/.....
/Description/blaapcVlin/baka/NameaplCv_hubala/......
/Description/aplCVintere/oldaplCvimg/NameaplCv_add/.....
I want to rename " Cv or CV or cV " >> "aplCv or aplCV or aplcV" in all folder by regular expression...
My script does look like:
#!/bin/sh
printf "Input your Directory path: -> "
read DIR
cd "$DIR"
FILECASE=$(find . -iname "*cv*")
LAST_DIR_NAME=""
for fdir in $FILECASE
do
if [[ -d $fdir ]];
then
LAST_DIR_NAME=$fdir
fi
FILE=$(echo $fdir | sed -e "s/\([Cc][Vv]\)/arpl\1/g")
echo "la file $FILE"
if ([[ -f $fdir ]] && [[ "$fdir" =~ "$LAST_DIR_NAME" ]]);
then
FILECASE=$(find . -iname "*cv*")
tmp=$(echo $LAST_DIR_NAME | sed -e "s/\([Cc][Vv]\)/arpl\1/g")
fdir=$(echo $fdir | sed -e 's|'$LAST_DIR_NAME'|'$tmp'|g')
fi
mv -- "$fdir" "$FILE"
done
But it throws an error ..:(
How could I write it to rename the files according to their folder names?
You can do like this
#!/bin/sh
printf "Input your Directory path: -> "
read DIR
cd "$DIR"
MYARRAY=$(find . -iname "*cv*" )
touch "tmpfile"
for fdir in $MYARRAY
do
echo "$fdir" >> "tmpfile"
done
MYARRAY=$(tac "tmpfile")
for fdir in $MYARRAY
do
cd "$fdir"
prev=$(cd -)
base=$(basename $fdir)
cd ..
nDIR=$(echo "$base" | sed -e "s/\([Cc][Vv]\)/arpl\1/g")
mv "$base" "$nDIR"
cd $prev
done
rm -f "tmpfile"
Also one issue i think tac command not included in Mac OS X.Instead tac use tail -r like MYARRAY=$(tail -r "tmpfile")
Always make a backup before playing with this kind of scripts.
You can try the following:
find . -iname '*cv*' -exec echo 'mv {} $(echo $(dirname {})/$(basename {}|sed s/cv/apl/gi))' \;|tac|xargs -i bash -c 'eval {}'
This uses -exec to print commands for renaming.
The second arguments are generated by using shell substitutions to replace cv with apl in the last part of the path.
tac is used to reverse the order of the commands, so that we do not rename a directory before working with its contents.
Finally, we eval the commands with bash.
Also, do not use -exec in a permanent script. Please read the security warnings about exec in the find man-page.

Use datestring in a filename to create folder directory and move files

The script I'm trying to pull of should move files to a destination folder and place them in "year/month/" folders according to the files name which starts with YYYY-MM-DD.
Example:
2013-08-03-image_name.png -> ~/B/uploads/2013/08/2013-08-03-image_name.png
2012-01-01-image_name.png -> ~/B/uploads/2012/01/2012-01-01-image_name.png
Plan of action
(1) Set path variables
source=~/Desktop/A/
targetPath=~/Desktop/B/uploads/
(2) Perform these actions on each file in $source
cd "$source";
for i in *.png
do
# STEP 3
# STEP 4
done
(3) Step 3: Image Optimization √
(4) Step 4: File away files to directory that machtes datename
(4a) Search for datestring in filename via ^(\d{4})-(\d{2}) and create $datePath, c.f. datePath=2013/08/. I image this something like this…
awk -F … somehow put the regex here with a search and replace "-" into "/"
and save it as a variable.
(4b) Create new target directory if it doesn't exist and move files there.
targetDir=$targetPath$datePath
mkdir -p $targetDir
mv -v "$i" "$destination"
PS: Bash would be nice.
I am providing you solution for finding target path for your files in pure BASH:
f='2013-08-03-image_name.png'
targetPath=~/Desktop/B/uploads/
[[ "$f" =~ ^([0-9]{4})-([0-9]{2}) ]] && \
echo "$targetPath${BASH_REMATCH[1]}/${BASH_REMATCH[2]}/$f"
OUTPUT:
~/Desktop/B/uploads/2013/08/2013-08-03-image_name.png
I'd use find + egrep to filter, then sed to build the name of the destination directory.
cd /src
IMAGES=`find . -type f -name '*.png' -print | egrep '^./[0-9]{4}-[0-9]{2}-[0-9]{2}-.+.png$'`
for IMG in $IMAGES; do
# optimize here
DIR=`echo $IMG | sed -E 's/^\.\/([0-9]{4})-([0-9]{2})-[0-9]{2}-.+.png/\1\/\2/'`
mkdir -p /dest/$DIR
mv /src/$IMG /dest/$DIR/
done
I think you will find glob useful and might find some inspiration in this question
Here's another bash solution, without using a regex/match:
srcdir=<whatever>
destdir=<whatever>
cd "${srcdir}"
for f in *-*-*-*.png
do
{ IFS=- read y m rest
[[ -d "${destdir}/${y}/${m}" ]] || mkdir -p "${destdir}/${y}/${m}"
echo mv "${f}" "${destdir}/${y}/${m}/${f}"
} <<< "${f}"
done
The for f in ... pattern may need some adjusting, depending on what other stuff you have in your source directory...
Remove the echo from in front of mv if you're satisfied with the proposed set of commands the above produces (or just pipe the whole thing into a subshell .... | bash).

How to search the file contents in multiple subversion repositories?

I've got multiple SVN repositories of different projects which I would like to search for the same search term / regex, but without checking out or updating each project and doing the search manually on each of them.
I'd like to know if it is possible to search the file contents in multiple SVN repositories for some search term (or regex).
Here is a script:
if [[ $# < 2 ]]; then
echo "Usage: $0 REGEX TARGET..."
echo "where REGEX is a regular expression for grep"
echo "and TARGET... is a list of SVN repositories"
exit
fi
regex=$1
shift
for svnroot in $#; do
for path in $(svn ls --recursive $svnroot); do
if [[ $path != */ ]]; then
svn cat $svnroot/$path \
| grep --label="$svnroot/$path" --with-filename $regex
fi
done
done