cd alias for moving between parallel directory structures - linux

Let's say I have the following directory structures (variable is the z or y or x or w directories):
/a/b/c/d/e/z/f/g/h/i/j/k
/a/b/c/d/e/y/f/g/h/i/j/k
/a/b/c/d/e/x/f/g/h/i/j/k
/a/b/c/d/e/w/f/g/h/i/j/k
How would I write an alias for the cd command (in bash) so that when I am in
/a/b/c/d/e/w/f/g/h or in
/a/b/c/d/e/w/f/g/h/i/j or in
/a/b/c/d/e/w/f/g/h/i/j/k
and type:
cd z
it would respectively take me in
/a/b/c/d/e/z/f/g/h or in
/a/b/c/d/e/z/f/g/h/i/j or in
/a/b/c/d/e/z/f/g/h/i/j/k
if I type:
cd y
it would respectively take me in
/a/b/c/d/e/y/f/g/h or in
/a/b/c/d/e/y/f/g/h/i/j or in
/a/b/c/d/e/y/f/g/h/i/j/k
of course if I type:
cd w
it should leave me where I am (already there).

it's probably easiest to use a function:
mycd() {
cd "/a/b/c/d/e/$1/${PWD#/a/b/c/d/e/*/}"
}
put that into your ~/.bashrc (or another file that you source with something like . mycd.bash), and use mycd x

Related

Concatenate a string with an array for recursively copy file in bash

I have a concatenation problem between a string and an array
I want to copy all the files contained in the directories stored in the array, my command is in a loop (to recursively copy my files)
yes | cp -rf "./$WORK_DIR/${array[$i]}/"* $DEST_DIR
My array :
array=("My folder" "...")
I have in my array several folder names (they have spaces in their names) that I would like append to my $WORK_DIR to make it possible to copy the files for cp.
But I always have the following error
cp: impossible to evaluate './WORKDIR/my': No such files or folders
cp: impossible to evaluate 'folder/*': No such files or folders
This worked for me
#!/bin/bash
arr=("My folder" "This is a test")
i=0
while [[ ${i} -lt ${#arr[#]} ]]; do
echo ${arr[${i}]}
cp -rfv ./source/"${arr[${i}]}"/* ./dest/.
(( i++ ))
done
exit 0
I ran the script. It gave me the following output:
My folder
'./source/My folder/blah-folder' -> './dest/./blah-folder'
'./source/My folder/foo-folder' -> './dest/./foo-folder'
This is a test
'./source/This is a test/blah-this' -> './dest/./blah-this'
'./source/This is a test/foo-this' -> './dest/./foo-this'
Not sure of the exact difference, but hopefully this will help.

Relative symlinks in Unix

I have a folder 'foo' which consist of file 'foo.v'. foo.v is a symlink to another file
foo.v -> ../foo2/foo.v
Now, I copy (or create link) another foo.v at first location (foo/) so that it becomes symlink to another file along with its original source file
- foo.v -> ../foo3/foo.v
- ../foo2/foo.v -> ../foo3/foo.v
Is something like this possible in linux ?
A symlink can point to a symlink:
$ echo test > 1
$ ln -s 1 2
$ ln -s 2 3
$ cat 3
test
$
These files look like this:
1
2 -> 1
3 -> 2
When moving or copying a symlink it behaves just like a file - the content is not changed:
$ cp 2 3
This would look like this:
1
2 -> 1
3 -> 1

Return an array from shell script to iterate/process in shell command line

I have a script that makes a list of calls to APIs and collects the response Codes into an array called updateResponses. I looked many placed and declare -p was recommended, but it's not working the way it's described or maybe I am using it wrong.
What I need : return the Array from the script and verify the elements by iterating over them.
My script.sh contains the highlights for this action:
updateResponses=()
do
..get statusCodes from list of calls in a loop...
updateResponses+=("$statusCode")
done
declare -p updateResponses
in my terminal after I execute this script, I see the array printed out but it is not an array to iterate over although it looks as if it was re-initialized to be used. Running echo "${#updateResponses[#]}" returns 0 as the size.
Example of the output after script.sh is done running :
declare -a updateResponses='([0]="200" [1]="200" [2]="200" [3]="200" [4]="200" [5]="200" [6]="200" [7]="200" [8]="200" [9]="200" [10]="200" [11]="200" [12]="200" [13]="200" [14]="200" [15]="200" [16]="200" [17]="200" [18]="200" [19]="200" [20]="200" [21]="200" [22]="200" [23]="200" [24]="200" [25]="200" [26]="200" [27]="200" [28]="200" [29]="200" [30]="200" [31]="200" [32]="200" [33]="200")'
You need to run the output of the script in the context of the current shell, e.g.
$ . <(arr=('a b' 'c d' 'e;f') ; declare -p arr)
$ echo ${arr[1]}
c d

Bash script archiving files according to number

I am currently writing a script that mounts a samba share, rsyncs the data to a local machine and archives into a directory structure (say /home/archive/). Currently when new pdfs are added, archiving done manually which seems like inefficient use of time
The files have the following structure
ABC140003.pdf
ABC140124.pdf
.
.
ABC144201.pdf
.
ABC146012.pdf
/home/archive/ has several directories 2010/, 2011/, 2012, 2013 etc
Basically, I need to break up the number to find the correct subdirectory to copy the file. First I extract the number
study_number=`echo $file | sed 's/[^0-9]//g'`
Then the year
year=20`echo $study_number | cut -c 1-2`
All the above pdf files belong in the subdirectory of 2014. Within 2014 or any other year directories there are the following subdirectories 2014/Blue/, /2014/Red/and/2014/Green/`. This corresponds to the 3rd integer in the number Blue(0), Red(4) and Green(6).
I use cases here to find what I have called study type
type_int=`echo $study_number | cut -c 3`
case "$type_int" in
0)
type_string="Blue"
;;
4) type_string="Red"
;;
6) type_string="Green"
;;
*) echo "$date: $file has unknown study type. Do not know where to place it" >> $logfile
continue
;;
esac
I now know the following files go in the following directories
ABC140003.pdf -> /home/archive/2014/Blue/
ABC140124.pdf -> /home/archive/2014/Blue/
.
.
ABC144201.pdf -> /home/archive/2014/Red/
.
ABC146012.pdf -> /home/archive/2014/Green/
I'd be happy if this was the end of the directory structure. However, there is another layer of subdirectories have been introduced so that no directory has more than 100 pdf files (Not my call).
For example /home/archive/2014/Blue/ has the following directories:
140001-0100/ 140101-0200/ 140201-0300/ 140301-0400/ 140401-0500/ 140501-0600/
etc
I now need to come up some logic such that the following files go to the following directories
ABC140003.pdf -> /home/archive/2014/Blue/140001-0100
ABC140124.pdf -> /home/archive/2014/Blue/140100-0124
.
.
ABC144201.pdf -> /home/archive/2014/Red/144200-4300
.
ABC146012.pdf -> /home/archive/2014/Green/146000-6100
I am stumped on how to logically determine that study ABC146012 should go in 146000-6100 in an elegant manner without resorting to multiple if statements for each of Red/ Blue/ and Green/
Here is a simplified version that needs some work but you get the idea (for a nice final solution, see #glenn jackman's solution):
Declare an associative array for the colors
$ declare -A colors
$ colors[0]=Blue
$ colors[4]=Red
$ colors[6]=Green
Then extract the needed information
$ study_number=$(sed 's/[^0-9]//g' <<< ABC140124.pdf);
$ year=${study_number:0:2};
$ type=${study_number:2:1};
$ color=${colors[$type]};
$ from="${study_number:0:$((${#study_number}-2))}01"
$ to="$((${study_number:0:$((${#study_number}-2))}+1))00"
and that gives:
$ echo /home/archive/$year/$color/$from-$to
/home/archive/14/Blue/140101-140200
(I assumed you wanted your intervals to be consistently numbered 'x01-(x+1)00')
You can create a function to simplify the process
build_dir() {
study_number=$(sed 's/[^0-9]//g' <<< $1);
year=${study_number:0:2};
type=${study_number:2:1};
color=${colors[$type]};
from="${study_number:0:$((${#study_number}-2))}01"
to="$((${study_number:0:$((${#study_number}-2))}+1))00"
echo "/home/archive/$year/$color/$from-$to"
}
It needs a bit of more defensive programming-related lines of code, but it can be used like this:
$ build_dir ABC146012.pdf
/home/archive/14/Green/146001-146100
colors=([0]=Blue [4]=Red [6]=Green)
get_destination() {
if [[ $1 =~ ([0-9][0-9])([0-9])([0-9]) ]]; then
printf "/home/archive/20%s/%s/%s%s%d01-%s%d00" \
${BASH_REMATCH[1]} \
${colors[${BASH_REMATCH[2]}]} \
${BASH_REMATCH[1]} \
${BASH_REMATCH[2]} \
${BASH_REMATCH[3]} \
${BASH_REMATCH[2]} \
$(( 1 + ${BASH_REMATCH[3]} ))
fi
}
for file in ABC140003.pdf ABC140124.pdf ABC144201.pdf ABC146012.pdf; do
echo "$file -> $(get_destination $file)"
done
ABC140003.pdf -> /home/archive/2014/Blue/140001-0100
ABC140124.pdf -> /home/archive/2014/Blue/140101-0200
ABC144201.pdf -> /home/archive/2014/Red/144201-4300
ABC146012.pdf -> /home/archive/2014/Green/146001-6100

How do I make a custom alias to print out a full path with custom text?

I want to make a alias for example if I type fullList it will print out a custom text with specific extension in full path listed the last modified the last something like
>fullList
file = /home/user/something/fileA.txt &
file = /home/user/something/fileB.txt &
file = /home/user/something/fileC.txt & <- the last modified.
If you want your exact example output, you're going to want to do something like.
#!/bin/bash
echo
for i in $(ls -trF *.txt); do
full_path="$(pwd $i)/$i"
echo "file = $full_path &"
done
And if you want to do a simple one line alias, do something like below.
> alias fullList="echo; for i in \$(ls -trF *.txt); do full_path=\"\$(pwd \$i)/\$i\"; echo \"file = \$full_path &\"; done"
> fullList
file = /some/path/oldest.txt &
file = /some/path/newer.txt &
...
file = /some/path/newest.txt &
Note, this is assuming you only want to find files, since the F flag for ls appends "/" to directories.
Function
Use a function instead of an alias. Henceforth, you will be able to pass argument
fullList() {
customText="$1"
for f in "$PWD"/* # list current dir files
do
printf "%s: %s\n" "$customText" "$PWD/$f"
done
}
Usage
Then run
$ fullList 'blabla'
blabla: /path/to/file1
blabla: /path/to/file2
blabla: /path/to/file2
Do you know about ?
The tree command ? Could be helpful to list directories content:
tree -f -L 1 $(pwd)/
/home
|-- /home/user1
`-- /home/user2

Resources