LINUX: List all directories, push into a bash array - linux

Here's the end result I am trying to:
I have over 15 users of an cloned instance of my application, sometimes I need to update files (they pretty much all stay the same--everything is dynamic. This is for updates/new features). I wrote a pretty simple bash script that I had to manually put each user from /home/ into the array. But I need this to scale.
How can I take a directory listing (something like a LS command) feed ONLY DIRECTORY names into then a bash array. Likely i'll want this command in the bash file though, because I'll want it to grab all users in the /home/ directory, push into the array (eg: webUsers( adam john jack )
Here's a snapshot of what my current script looks like (non-dynamic user listing)
webUsers( adam john jack )
for i in "${webUsers[#]}"
do
cp /home/mainSource/public_html/templates/_top.tpl /home/$i/public_html/templates
done
How do I achieve this?

Do this:
webUsers=(/home/*/)
and the contents will look like:
$ declare -p webUsers
declare -a webUsers='([0]="/home/adam/" [1]="/home/jack/" [2]="/home/john")'
$ echo ${webUsers[1]}
/home/jack/
Or, if you don't want the parent directory:
pushd /home
webUsers=(*/)
popd
and you'll get:
$ declare -p webUsers
declare -a webUsers='([0]="adam/" [1]="jack/" [2]="john")'
$ echo ${webUsers[1]}
jack/

The following script will loop over all users with directories in /home. It will also unconditionally try to create the /public_html/templates directory. If it doesn't yet exist, it will get created. If it does exist, this command does essentially nothing.
#!/bin/bash
cd /home
userarr=( */ );
for user in "${userarr[#]%*/}"; do
mkdir -p "/home/${user}/public_html/templates"
cp "/home/mainSource/public_html/templates/_top.tpl /home/${user}/public_html/templates"
done

It may be easier to make a link to the source directory, and then you can just update it in one place.
Just set up each users directory so that the common files are all pulled from a directory called common_files (or whatever you like), and then run this command in each home directory:
ln -s /location/of/files/they/need common_files
update /location/of/files/they/need and it automatically propagates.

With bash you can actually make this pretty short and simple. To list the current directory and store it into an array:
ls . | readarray i
or
ls . | bash -c 'readarray i'
To use the data:
ls . | bash -c 'readarray i && for j in ${i[*]}; do <-command->; done'

Related

Directory structure variations in bash script

I have a shell script myautoappupgrade.sh where I automate a process of application upgrade. The script has to be run on few different servers. Unfortunately, the application is located in slightly different directory on each server - the number for parent directory varies between 1-20. How I can modify the script, so that the directory can be replaced by some sort of variable? I don't want to edit the script for each server because there are many directory queries in the automation script.
example:
cd /ae1/apps/myapp/upgradefiles/
unzip file.zip
./install.sh
the directory slightly changes on another server:
cd /ae2/apps/myapp/upgradefiles/
unzip file.zip
./install.sh
and another..
cd /ae3/apps/myapp/upgradefiles/
unzip file.zip
./install.sh
Try something like this:
#!/bin/bash
num=$1
cd /ae${num}/apps/myapp/upgradefiles/file.zip
unzip file.zip
./install.sh
Then call the script with the number as first argument:
myautoappupgrade.sh 1
The simple and obvious solution is to not hard-code the directory at all. Modify the script so it accepts the parent directory as an argument, or just cd into the parent directory before running the script.
Perhaps something like this:
while read server dir; do
ssh "$server" "cd '$dir' && unzip apps/myapp/upgradefiles/file.zip/file.zip && ./install.sh"
done <<\:
ernie /ae1
bert /ae2
cookiemonster /home/cmonster/anN
:
It would probably be even better if you unzipped into a temporary directory, but hopefully this should get you moving in the right direction.
Of course, if you can be sure that /ae[0-1] is always there and there is only one match,
cd /ae[0-9]/apps/myapp/upgradefiles/file.zip
would do what you are asking.
(Do you really have a file named file.zip inside a directory also named file.zip? I'm guessing actually take away the file.zip from the end of the cd path.)
By simply using:
cd /ae*/apps/myapp/upgradefiles/
The * will expand any character.

How to create folder and cd into it with one command

I'm looking for a command that would create a directory and bring me to it directly after, similar to:
$ mkdir project-one-business-dev-2
$ cd project-one-business-dev-2
I don't want to type the project's name twice because it's too long (I know I can use tab, but what if there are similar names?). Maybe only one command can do it.
A process can't change the working directory of it's parent process. That makes it impossible for an external command like mkdir to set the working directory of the calling shell to the newly created folder.
But you can create a bash function for that purpose. Put this for example into your .bashrc:
mkcd() {
mkdir -p "${1}"
cd "${1}"
}
You can do it like this:
mkdir project-one-business-dev-2 && cd "$_"
for more information check out this post on AskUbuntu

How to navigate to a single child directory without knowing its name using shell command?

I need to run a script in a remote machine from my JAVA code using runCommand() method. Now I can't always know the full path of the script as a particular directory name keeps changing. For example the path looks like this : /a/b/xxxxx/script . xxxx is the directory name that keeps changing and its the only single directory under /a/b/. Is there any shell command using which I can get the directory name ? I know using JAVA,but I specifically need shell command.
If there is only a single self-directory, another fool-proof way of doing it would be
cd */.
*/. is that this expands to the "self directory" (named .) in any subdirectory, which is of course the sub-directory itself. Refer the below example of how it works.
E.g.
$ pwd
/home/dude/
$ mkdir -p a/b/ldsnds/c
$ cd a/b/*/.
$ pwd
/home/dude/a/b/ldsnds
$ cd -
/home/dude/
$ cd a/b/*/./c
$ pwd
/home/dude/a/b/ldsnds/c
Below should give you the name of the directory in the directory "b".
$ find /a/b -type d -maxdepth 1 2> /dev/null
If you are so sure that it would always be one directory in /a/b then just store the output of find in a variable and move ahead.
Note: 2> /dev/null is just to get rid of errorneous warnings.

what is the difference between . and `` operation in shell script

Request to need a help or information of the two operators . and `` in linux
e.g.
$ cp /home/uddi/root/hello `pwd`
and
$ cp /home/uddi/root/hello .
Please suggest me
A small difference occurs after mkdir /tmp/lost; cd /tmp/lost; rmdir /tmp/lost.
After these stupid commands pwd will be a filename (/tmp/lost) and the current dir . does not exist.
I think you want an error when you try to copy a file in the "current" dir, so I would prefer the .. It will also avoid an extra command.
When you enclose something between back-ticks, the shell will run the contents and use the output from that/those command/s as an argument for the main command being run. In your example, the shell will run the pwd command and use its output as the 2nd argument to the cp call.
In your second example, the . character is a link to the current directory. The reason that both do the same thing is that . links to the current directory and pwd will print out the current working directory, which are the same. In this case, you are using two methods to expand to the same path.
EDIT:
You can see somewhat how . works by running ls -a in any directory. It will show you the . and .. directories, which are filesystem-level links to the current and parent directory, respectively.

One command to create and change directory

I'm searching for just one command — nothing with && or | — that creates a directory and then immediately changes your current directory to the newly-created directory. (This is a question someone got for his exams of "linux-usage", he made a new command that did that, but that didn't give him the points.) This is on a debian server if that matters.
I believe you are looking for this:
mkdir project1 && cd "$_"
define a bash function for that purpose in your $HOME/.bashrc e.g.
function mkdcd () {
mkdir "$1" && cd "$1"
}
then type mkdcd foodir in your interactive shell
So stricto sensu, what you want to achieve is impossible without a shell function containing some && (or at least a ; ) ... In other words, the purpose of the exercise was to make you understand why functions (or aliases) are useful in a shell....
PS it should be a function, not a script (if it was a script, the cd would affect only the [sub-] shell running the script, not the interactive parent shell); it is impossible to make a single command or executable (not a shell function) which would change the directory of the invoking interactive parent shell (because each process has its own current directory, and you can only change the current directory of your own process, not of the invoking shell process).
PPS. In Posix shells you should remove the functionkeyword, and have the first line be mkdcd() {
For oh-my-zsh users: take 'directory_name'
Reference: Official oh-my-zsh github wiki
Putting the following into your .bash_profile (or equivalent) will give you a mkcd command that'll do what you need:
# mkdir, cd into it
mkcd () {
mkdir -p "$*"
cd "$*"
}
This article explains it in more detail
I don't think this is possible but to all people wondering what is the easiest way to do that (that I know of) which doesn't require you to create your own script is:
mkdir /myNewDir/
cd !$
This way you don't need to write the name of the new directory twice.
!$ retrieves the last ($) argument of the last command (!).
(There are more useful shortcuts like that, like !!, !* or !startOfACommandInHistory. Search on the net for more information)
Sadly mkdir /myNewDir/ && cd !$ doesn't work: it retrieves the last of argument of the previous command, not the last one of the mkdir command.
Maybe I'm not fully understanding the question, but
>mkdir temp ; cd temp
makes the temp directory and then changes into that directory.
mkdir temp ; cd temp ; mv ../temp ../myname
You can alias like this:
alias mkcd 'mkdir temp ; cd temp ; mv ../temp ../'
You did not say if you want to name the directory yourself.
cd `mktemp -d`
Will create a temp directory and change into it.
Maybe you can use some shell script.
First line in shell script will create the directory and second line will change to created directory.

Resources