I've been trying to create a bash script that can move up a directory. I created this script, but when ran it does not execute anything. I tried adding a print statement to it, and that does work. Is there a certain way I should be executing this?
Script:
#!/usr/bin/zsh
DIR=$1
NUM=$PWD
for ((c=1; c <= DIR; c++))
do
echo $NUM
cd $NUM/..
done
If I understand, you like to move a directory up in the directory tree.
This is a script make aliases in .bashrc Like: alias up1='cd../' alias up2='cd../../' and so on, I limit the depth 9. If you Run it multiple times the script only crate the not existing entrys. May I will able to make it delete entry if you give less depth then script would manage this alias.
Not exactly you looking for but since script running in they own instance you cannot make them affect your current shell. Also after this script create aliases you need re authenticate or open a new shell, from that point they will work till you not delete the alias entry from .bashrc.
#!/bin/sh
[[ ! $# == 1 ]] && echo "Only one parameter accepted" && exit 1
[[ $( echo $1 | grep -c ^[1-9]$ ) -eq 0 ]] && echo "parameter must be between 1 and 9" && exit 1
cdcommand=""
for (( i = 1 ; i <= $1 ; i++ )); do
cdcommand=$(echo $cdcommand | sed 's/^/\.\.\//g')
[[ $( cat ~/.bashrc | grep -c "alias up$i='cd $cdcommand' ") == 0 ]] &&
echo "alias up$i='cd $cdcommand' " >> ~/.bashrc
done
Related
This question already has an answer here:
Why variable values are lost after terminating the loop in bash? [duplicate]
(1 answer)
Closed 2 years ago.
I would like to make a script which allow me to execute a command which inherit environment variables from any PID.
Here the script I made :
#!/bin/sh
VARS=$(cat -A /proc/1/environ | tr "^#" "\n")
COMMAND=""
# sh compatible loop on a variable containing multiple lines
printf %s "$VARS" | while IFS='\n' read -r var
do
if [ "$var" != "" ]; then
export "$var"
fi
done
exec "$#"
I though exported variables would be available for the child process (created by exec) but this is obviously not the case because sh my_script.sh printenv doesn't show environment variables which are in /proc/1/environ.
I also tried the following script :
#!/bin/sh
VARS=$(cat -A /proc/1/environ | tr "^#" "\n")
COMMAND=""
# sh compatible loop on a variable containing multiple lines
printf %s "$VARS" | while IFS='\n' read -r var
do
if [ "$var" != "" ]; then
# Replace 'VAR=var' by 'VAR="var"' for eval
# sed replace only the first occurence of the '=' due of the missing /g parameter
escaped=$(echo $var | sed -e 's/=/="/')\"
COMMAND="${COMMAND} ${escaped}"
fi
done
COMMAND="${COMMAND} $#"
eval $COMMAND
However, it looks like eval doesn't export variables even if the evaluated command looks like VAR=value my_command.
How I am supposed to achieve my needs ?
Thanks in advance
That one should work (tested on RHEL 7)
#!/bin/bash
locPROC=$1
locCMD=$2
if [[ -z $locPROC || -z $locCMD ]]; then
exit
fi
if [[ -r /proc/${locPROC}/environ ]]; then
while IFS= read -r -d '' line; do
#Making sure it's properly quoted
locVar="${line/=/=\"}\""
#You probably don't want to mess with those
if [[ ${locVar:0:1} != "_" && ${locVar} != A__z* ]]; then
eval "$locVar"
eval "export ${locVar%%=*}"
fi
done < "/proc/${locPROC}/environ"
$locCMD
else
echo "Environment file is either inexistant or unreadable"
fi
EDITED : According to comments (still use eval...got to read more :) )
I am trying to have an alias with if-then-else condition
on a command result.
the alias will get a file pattern
if there is just one file it will open the file
if there is more or less then 1 files - it will indicate with a message.
the alias I have tried is:
alias atest 'if \("ls \!:1" > 0 \) "nedit ls \!:1" else "echo cant open the file" '
There are a couple of ways, most of them are not very elegant, but the following is the best looking and easiest to create that I have discovered:
alias aliasname '`if (condition == check) echo "echo"` >&/dev/null && code_if_true || code_if_false'
You have the ability to nest if statements following this format, and can also use it as a checker for arguments if you change the interior of the if statement to be
if ("\!:1" =~ "check")
The >&/dev/null is to clean up the output of the function, but is not necessary. If you are interested, there is also a way to make for statements within aliases, but that method is a lot less elegant. I haven't used it but it is necessary if you wish to create an alias with a varying number of arguments. Again, that one is ugly, so at that point I'd just write a function.
You can't do this with an alias. An alias can only expand into a one-line command, but if requires multiple lines.
Instead, use a shell script. The script doesn't have to be in the same language you use interactively, so you can use POSIX shell, which is generally considered much better for programming than C shell (see Csh Programming Considered Harmful).
#!/bin/sh
if [ $# -eq 1 ]
then nedit "$1"
else
echo "Can't open the file"
exit 1
fi
Put this in a file named atest, give it execute permissions, and put it in a directory that's in your $PATH.
Building on Jonathan Roberts solution. This is part of a bash script on the local server. Checks for user XXXXX if true, sends through ssh the BASH command. Otherwise sends the TCSH command. The command checks to see if a directory exists returns true or false
if [[ ${LOCAL_USER} == "XXXXX" ]]; then
LOCAL_DIR_EXIST_CHECK=$(ssh -v -q -i ~/.ssh/"${LOCAL_SSH_KEY_FILE}" "${LOCAL_USER}#${LOCAL_SERVER}" "if [[ -d ${LOCAL_CLIENT_DIRECTORY} ]];then echo 'TRUE'; else echo 'FALSE'; fi")
else
LOCAL_DIR_EXIST_CHECK=$(ssh -v -q -i ~/.ssh/"${LOCAL_SSH_KEY_FILE}" "${LOCAL_USER}#${LOCAL_SERVER}" '`if ( -d ' ${LOCAL_CLIENT_DIRECTORY} ') echo "echo"` > & /dev/null && echo TRUE || echo FALSE')
fi
Actually, tcsh can have aliases with multiple lines in them. Just finish each line with backslash () and continue writing the alias on a next line.
~> alias atest 'set __atest_pattern="\!:1" \
? set __atest_files=( "`ls -d $__atest_pattern`" ) \
? if ( $#__atest_files == 1 ) then \
? nedit "$__atest_files[1]" \
? else if ( $#__atest_files > 1 ) then \
? echo "Too many files ($#__atest_files) are matched to '\''$__atest_pattern'\''" \
? endif'
~> alias atest
set __atest_pattern="!:1"
set __atest_files=( "`ls -d $__atest_pattern`" )
if ( $#__atest_files == 1 ) then
nedit "$__atest_files[1]"
else if ( $#__atest_files > 1 ) then
echo "Too many files ($#__atest_files) are matched to '$__atest_pattern'"
endif
~> atest *
Too many files (73) are matched to '*'
~> atest dummy
ls: cannot access dummy: No such file or directory
~> atest /dummy/*
ls: No match.
~> atest .cshrc
# Actually nedit was invoked here
~>
Using #JonathanRoberts answer I was able to finally improve an alias for exit that I use in shells inside screen so that I don't accidentally exit when I really want to detach. So, now I can override the faked exit with exit now if I want and really exit:
In ~/.tcshrc
if ($?TERM && $TERM =~ screen.*) then
#OLD ALIAS# alias exit "echo 'exit disabled (via alias)'; screen -d"
alias exit '`if ("\!:$" == "now") echo "echo"` >&/dev/null && exec false || echo "really? use: exit now" ; screen -d'
endif
I am looking into how a particular exploit works, and I chose to look at one in the program 'chkrootkit' which allows for any user to run a malicious file as root. The source code for this vulnerable shellscript is as follows
slapper (){
SLAPPER_FILES="${ROOTDIR}tmp/.bugtraq ${ROOTDIR}tmp/.bugtraq.c"
SLAPPER_FILES="$SLAPPER_FILES ${ROOTDIR}tmp/.unlock ${ROOTDIR}tmp/httpd \
${ROOTDIR}tmp/update ${ROOTDIR}tmp/.cinik ${ROOTDIR}tmp/.b"a
SLAPPER_PORT="0.0:2002 |0.0:4156 |0.0:1978 |0.0:1812 |0.0:2015 "
OPT=-an
STATUS=0
file_port=
if ${netstat} "${OPT}"|${egrep} "^tcp"|${egrep} "${SLAPPER_PORT}">
/dev/null 2>&1
then
STATUS=1
[ "$SYSTEM" = "Linux" ] && file_port=`netstat -p ${OPT} | \
$egrep ^tcp|$egrep "${SLAPPER_PORT}" | ${awk} '{ print $7 }' |
tr -d :`
fi
for i in ${SLAPPER_FILES}; do
if [ -f ${i} ]; then
file_port=$file_port $i
STATUS=1
fi
done
if [ ${STATUS} -eq 1 ] ;then
echo "Warning: Possible Slapper Worm installed ($file_port)"
else
if [ "${QUIET}" != "t" ]; then echo "not infected"; fi
return ${NOT_INFECTED}
fi
}
I know that the reason the exploit works is because the line 'file_port=$file_port $i' will execute all files specified in $SLAPPER_FILES as the user chkrootkit is running (usually root), if $file_port is empty, because of missing quotation marks around the
variable assignment."
My question is why does the command
file_port=$file_port $i
result in execution of the file? Assuming that $i refers to the path of the file (/tmp/update)
I can see that file_port might be changed to some long netstat command in the previous if statement, is this something to do with it?
I've been trying to get my head around this all day to no avail, so at this point any help will be greatly appreciated :)
This is the one-shot variable assignment feature of any Bourne shell. Any command can be prefixed with zero or more variable assignments:
VAR1=VALUE1 VAR2=VALUE2 command arguments ...
Runs command arguments ... with the respective environment variables set for just this command. A typical use might be
EDITOR=vim crontab -e
I want to recursively loop through all subdirectories within the current directory.
for i in *
this only iterates through all the files in the current directory. How do you make it so that if the file it is looking at is a directory, to enter that directory and recursively look through that directory too and so on and so forth.
EDIT: sorry should have been more specific. i cant use ls -R, as i want to display it in a tree structure with a certain format type. I have heard there are commands which can do this but i have to use a loop. cannot use "find" either...
Here is a function to do what you need. Call it with recp 0 in the current directory.
function recp
{
lvl=$(($1 + 1))
for f in *
do
j=0
while [[ $j -lt $lvl ]]
do
echo -n " "
j=$(($j+1))
done
echo $f
[[ -d $f ]] && ( cd $f && recp $lvl )
done
}
I'm not very good at bash scripting
but the example below goes through all the directories.
You can replace the echo command with whatever you like.
I'm sure the style of this example can be improved.
Also did you consider the command "tree"?
Good luck.
#!/bin/bash
function recursiveList
{
if [ -d $1 ]
then
cd $1
for x in *
do
recursiveList $x
done
cd ..
else
echo $1
fi
}
for i in *
do
recursiveList $i
done
I want to create a bash alias to do the following:
Assume I am at the following path:
/dir1/dir2/dir3/...../dirN
I want to go up to dir3 directly without using cd ... I will just write cdd dir3 and it should go directly to /dir1/dir2/dir3. cdd is my alias name.
I wrote the following alias, but it doesn't work:
alias cdd='export newDir=$1; export myPath=`pwd | sed "s/\/$newDir\/.*/\/$newDir/"`; cd $myPath'
Simply it should get the current full path, then remove anything after the new destination directory, then cd to this new path
The problem with my command is that $1 doesn't get my input to the command cdd
This is a slightly simpler function that I think achieves what you're trying to do:
cdd() { cd ${PWD/$1*}$1; }
Explanation:
${PWD/$1*}$1 takes the current working directory and strips off everything after the string passed to it (the target directory), then adds that string back. This is then used as an argument for cd. I didn't bother adding any error handling as cdwill take care of that itself.
Example:
[atticus:pgl]:~/tmp/a/b/c/d/e/f $ cdd b
[atticus:pgl]:~/tmp/a/b $
It's a little ugly, but it works.
Here's a function - which you could place in your shell profile - which does what you want; note that in addition to directory names it also supports levels (e.g., cdd 2 to go up 2 levels in the hierarchy); just using cdd will move up to the parent directory.
Also note that matching is case-INsensitive.
The code is taken from "How can I replace a command line argument with tab completion?", where you'll also find a way to add complementary tab-completion for ancestral directory names.
cdd ()
{
local dir='../';
[[ "$1" == '-h' || "$1" == '--help' ]] && {
echo -e "usage:
$FUNCNAME [n]
$FUNCNAME dirname
Moves up N levels in the path to the current working directory, 1 by default.
If DIRNAME is given, it must be the full name of an ancestral directory (case does not matter).
If there are multiple matches, the one *lowest* in the hierarchy is changed to." && return 0
};
if [[ -n "$1" ]]; then
if [[ $1 =~ ^[0-9]+$ ]]; then
local strpath=$( printf "%${1}s" );
dir=${strpath// /$dir};
else
if [[ $1 =~ ^/ ]]; then
dir=$1;
else
local wdLower=$(echo -n "$PWD" | tr '[:upper:]' '[:lower:]');
local tokenLower=$(echo -n "$1" | tr '[:upper:]' '[:lower:]');
local newParentDirLower=${wdLower%/$tokenLower/*};
[[ "$newParentDirLower" == "$wdLower" ]] && {
echo "$FUNCNAME: No ancestral directory named '$1' found." 1>&2;
return 1
};
local targetDirPathLength=$(( ${#newParentDirLower} + 1 + ${#tokenLower} ));
dir=${PWD:0:$targetDirPathLength};
fi;
fi;
fi;
pushd "$dir" > /dev/null
}
I agree with mklement0, this should be a function. But a simpler one.
Add this to your .bashrc:
cdd () {
newDir="${PWD%%$1*}$1"
if [ ! -d "$newDir" ]; then
echo "cdd: $1: No such file or directory" >&2
return 1
fi
cd "${newDir}"
}
Note that if $1 (your search string) appears more than once in the path, this function will prefer the first one. Note also that if $1 is a substring of a path, it will not be found. For example:
[ghoti#pc ~]$ mkdir -p /tmp/foo/bar/baz/foo/one
[ghoti#pc ~]$ cd /tmp/foo/bar/baz/foo/one
[ghoti#pc /tmp/foo/bar/baz/foo/one]$ cdd foo
[ghoti#pc /tmp/foo]$ cd -
/tmp/foo/bar/baz/foo/one
[ghoti#pc /tmp/foo/bar/baz/foo/one]$ cdd fo
cdd: fo: No such file or directory
If you'd like to include the functionality of going up 2 levels by running cdd 2, this might work:
cdd () {
newDir="${PWD%%$1*}$1"
if [ "$1" -gt 0 -a "$1" = "${1%%.*}" -a ! -d "$1" ]; then
newDir=""
for _ in $(seq 1 $1); do
newDir="../${newDir}"
done
cd $newDir
return 0
elif [ ! -d "$newDir" ]; then
echo "cdd: $1: No such file or directory" >&2
return 1
fi
cd "${newDir}"
}
The long if statement verifies that you've supplied an integer that is not itself a directory. We build a new $newDir so that you can cd - to get back to your original location if you want.