open bash subshell in specified directory - bash

When I run the bash command it opens a new subshell in the current directory. Is there a way to open the new bash shell in a different directory?
This is what it does:
$ pwd
/original/location
$ bash
$ pwd
/original/location
I'd like to do something like this
$ pwd
/original/location
$ bash "some magic command to start it in a /another/location"
$ pwd
/another/location
$ exit
$ pwd
/original/location
EDIT
I also want it so that when I exit the subshell I return to the original location

Simply cd to the directory before you start the subshell. To avoid changing directory in the parent shell, use parentheses to limit the change to a(nother) subshell:
(cd /another/location && bash)

Related

How can I redirect stdout and stderr with variant?

Normally, we use
sh script.sh 1>t.log 2>t.err
to redirect log.
How can I use variant to log:
string="1>t.log 2>t.err"
sh script.sh $string
You need to use 'eval' shell builtin for this purpose. As per man page of bash command:
eval [arg ...]
The args are read and concatenated together into a single command. This command is then read and exe‐
cuted by the shell, and its exit status is returned as the value of eval. If there are no args, or
only null arguments, eval returns 0.
Run your command like below:
eval sh script.sh $string
However, do you really need to run script.sh through sh command? If you instead put sh interpreter line (using #!/bin/sh as the first line in your shell script) in your script itself and give it execute permission, that would let you access return code of ls command. Below is an example of using sh and not using sh. Notice the difference in exit codes.
Note: I had only one file try.sh in my current directory. So ls command was bound to exit with return code 2.
$ ls try1.sh try1.sh.backup 1>out.txt 2>err.txt
$ echo $?
2
$ eval sh ls try1.sh try1.sh.backup 1>out.txt 2>err.txt
$ echo $?
127
In the second case, the exit code is of sh shell. In first case, the exit code is of ls command. You need to make cautious choice depending on your needs.
I figure out one way but it's ugly:
echo script.sh $string | sh
I think you can just put the name into a string variable
and then use data redirection
file_name="file1"
outfile="$file_name"".log"
errorfile="$file_name"".err"
sh script.sh 1> $outfile 2> $errorfile

Changing ksh dir when exiting bash mode

My default shell is ksh but I like to use bash to browse directories so when I found what I wanted I exit from bash and I wanted to have my ksh dir set to the same dir as bash was when I exited it.
for example:
1 - Log in
2 - $ ps -p && | tail -1 | awk '{print $4}'
ksh
$ pwd
/home/myuser
3 - $ bash
$ ps -p && | tail -1 | awk '{print $4}'
bash
$ pwd
/home/myuser
$ cd dir1
$ cd dir2
$ pwd
/home/myuser/dir1/dir2
$ exit
4 $ ps -p && | tail -1 | awk '{print $4}'
ksh
$ pwd
/home/myuser
So at the end of step 3 when I exited bash shell I would like to have my ksh to have the same dir as bash had.
So in the example above when I ran step 4 I would like to to have my pwd set to /home/myuser/dir1/dir2 automaticaly. Does anyone know how to do that trick ?
I know that if I type ksh instead of exit I will have the same dir but I don't want to start a new session everytime I need to "browse" dirs.
Environment: AIX
When bash exits, it executes the file ~/.bash_logout if it exists. So first write a .bash_logout that records the current directory:
pwd >~/.place
Then write a ksh function that calls bash, then does a cd to the directory recorded in the file:
bashcd()
{
bash --login
cd $(cat ~/.place)
}
The --login is needed because bash will not run .bash_logout if it isn't a "login shell". Define the function in your ~/.kshrc file, then use bashcd instead of bash.
I end up resolving like this:
I added to my ~/.bash_logout the following line:
pwd >~/.place
Then I created this alias in my .kshrc
alias bashcd = 'bash -l;cd `cat ~/.place`'
it's working like a charm.
It can't be done. A sub-shell, such as your invocation of bash, is completely unable to influence its parent.

Piping `cd` or `popd` output prevents changing directories?

I understand that since | initiates a new process for the command(s) after the pipe, any shell command of the form cmd | cd newdir (where cmd does not change the current working directory) will leave the original process's working directory unchanged. (Not to mention that this is a bit silly since cd doesn't read input from stdin.)
However, on my machine (a CentOS 6 box, using bash, ksh, or zsh), it appears that the following command also fails to change directories:
cd newdir | cat
(Please ignore how silly it is to pipe output to cat here; I'm just trying to make a simple example.)
Why is this? Is there a way around this problem? Specifically, I'm trying to write an alias that uses popd but catches the output, discards stdout, and re-outputs stderr.
(For the curious, this is my current, non-working alias: popd 2>&1 >/dev/null | toerr && lsd. Here, toerr just catches stdin, outputs it to stderr, and returns the number of lines read/printed. lsd is a directory-name-and-contents printer that should only execute if the popd is successful. The reason I'm sending stderr to stdout, piping it, catching it, and re-outputting it on stderr is just to get it colored red using stderred, since my shell session isn't loaded with LD_PRELOAD, so Bash built-ins such as popd don't get the red-colored stderr.)
In bash, dash and ash, each command in a pipeline runs in a subshell.
In zsh, ksh, and bash with shopt -s lastpipe, all except the last command in the pipeline run in subshells.
Since cd -- as well as variables, shell options, ulimits and new file descriptors -- only affects the current process, their effects will not affect the parent shell.
Examples:
# Doesn't change directory
cd foo | cat
pwd
# Doesn't set $bar on default bash (but does on zsh and ksh)
echo foo | read bar
echo "$bar"
# Doesn't change the ulimit
ulimit -c 10000 2>&1 | grep "not permitted"
ulimit -c
The same also applies to other things that generate subshells. None of the following will change the directory:
# Command expansion creates a subshell
echo $(cd foo); pwd
# ( .. ) creates a subshell
( cd foo ); pwd
# Backgrounding a process creates a subshell
cd foo & pwd
To fix it, you have to rewrite your code to run anything that affects the environment in the main shell process.
In your particular case, you can consider using process substitution:
popd > /dev/null 2> >(toerr) && lsd
This has the additional benefit of only running lsd when popd is successful, rather than when toerr is successful like your version does.

Difference between "./" and "sh" in UNIX

Sometimes i see that few scripts are executed through "sh" command and sometimes through "./" command.I am not able to understand the exact difference between them.Please help me out .
sh file executes a shell-script file in a new shell process.
. file executes a shell-script file in the current shell process.
./file will execute the file in the current directory. The file can be a binary executable, or it can start with a hashbang line (the first line of the file in form of #!...., for example #!/usr/bin/ruby in a file would signify the script needs to be executed as a Ruby file). The file needs to have the executable flag set.
For example, if you have the script test.sh:
#!/bin/sh
TEST=present
and you execute it with sh test.sh, you'd launch a new sh (or rather bash, most likely, as one is softlinked to the other in modern systems), then define a new variable inside it, then exit. A subsequent echo $TEST prints an empty line - the variable is not set in the outer shell.
If you launch it using . test.sh, you'd execute the script using the current shell. The result of echo $TEST would print present.
If you launch it using ./test.sh, the first line #!/bin/sh would be detected, then it would be exactly as if you wrote /bin/sh ./test.sh, which in this case boils down to the first scenario. But if the hashbang line was, for example, #!/usr/bin/perl -w, the file would have been executed with /usr/bin/perl -w ./test.sh.
In simple words, sh file1 executing sh command/executable with file1 as a parameter. In this case file1 doesn't require execute privilege as sh executable read and intercept the commands in the file.
./file1 its nothing but running/executing an executable file file1, hence it requires executable privileges. In this case it executes on the shell mentioned in the shebang #!/bin/sh if its not mentioned then its on the current shell.
Hoping the above statements are not chaos :)
With sh , we can run a script that doesn’t have execute permission set on it, we run it as argument for sh, but ./ needs the permission as it is supposed to be an executable.
In both cases, new shell will be created to run the script. See the below example:
root#ub18:~/shell# vi test1.sh
#!/bin/bash
my_var=hello
echo $my_var
#Shows the current shell processid
echo $$
root#ub18:~/shell# echo $$
1896
root#ub18:~/shell# sh test1.sh
hello
2093
root#ub18:~/shell# ./test1.sh
-su: ./test1.sh: Permission denied
root#ub18:~/shell# chmod +x ./test1.sh
root#ub18:~/shell# ./test1.sh
hello
2102
root#ub18:~/shell# ./test1.sh
hello
2103
root#ub18:~/shell# ./test1.sh
hello
2104
root#ub18:~/shell# sh test1.sh
hello
2106
when your file is not executable you can't run using ./file_name.sh normally you can run by sh file_name.sh if you change your file to executable chmod a+x file_name.sh you can run your file by ./file_name.sh

using alias in shell script? [duplicate]

This question already has answers here:
How to use aliases defined in .bashrc in other scripts?
(6 answers)
Closed 2 years ago.
My alias defined in a sample shell script is not working. And I am new to Linux Shell Scripting.
Below is the sample shell file
#!/bin/sh
echo "Setting Sample aliases ..."
alias xyz="cd /home/usr/src/xyz"
echo "Setting done ..."
On executing this script, I can see the echo messages. But if I execute the alias command, I see the below error
xyz: command not found
am I missing something ?
source your script, don't execute it like ./foo.sh or sh foo.sh
If you execute your script like that, it is running in sub-shell, not your current.
source foo.sh
would work for you.
You need to set a specific option to do so, expand_aliases:
shopt -s expand_aliases
Example:
# With option
$ cat a
#!/bin/bash
shopt -s expand_aliases
alias a="echo b"
type a
a
$ ./a
# a is aliased to 'echo b'
b
# Without option
$ cat a
#!/bin/bash
alias a="echo b"
type a
a
$ ./a
./a: line 3: type: a: not found
./a: line 4: a: command not found
reference: https://unix.stackexchange.com/a/1498/27031 and https://askubuntu.com/a/98786/127746
sourcing the script source script.sh
./script.sh will be executed in a sub-shell and the changes made apply only the to sub-shell. Once the command terminates, the sub-shell goes and so do the changes.
OR
HACK: Simply run following command on shell and then execute the script.
alias xyz="cd /home/usr/src/xyz"
./script.sh
To unalias use following on shell prompt
unalias xyz
If you execute it in a script, the alias will be over by the time the script finishes executing.
In case you want it to be permanent:
Your alias is well defined, but you have to store it in ~/.bashrc, not in a shell script.
Add it to that file and then source it with . .bashrc - it will load the file so that alias will be possible to use.
In case you want it to be used just in current session:
Just write it in your console prompt.
$ aa
The program 'aa' is currently not installed. ...
$
$ alias aa="echo hello"
$
$ aa
hello
$
Also: From Kent answer we can see that you can also source it by source your_file. In that case you do not need to use a shell script, just a normal file will make it.
You may use the below command.
shopt -s expand_aliases
source ~/.bashrc
eval $command
Your alias has to be in your .profile file not in your script if you are calling it on the prompt.
If you put an alias in your script then you have to call it within your script.
Source the file is the correct answer when trying to run a script that inside has an alias.
source yourscript.sh
Put your alias in a file call ~/.bash_aliases and then, on many distributions, it will get loaded automatically, no need to manually run the source command to load it.

Resources