Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game. |
Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
|
|
06-09-2024, 10:35 PM
|
#1
|
LQ Newbie
Registered: Jun 2023
Posts: 18
Rep:
|
Walking Up Directories For Every ..
Hello,
I am currently trying to implement a basic shell function that will for every .. I type into the shell. This is actually being aped from magicdots for zsh. I know the underlying logic, but am mainly running into trouble with actually interfacing with the shell itself. I do not know if that makes sense, so I will just get the code in hopes it helps other understand. Currently I have the following function.
Code:
_walk() {
case "${1}" in
..*)
i=0
directories_to_walk=$(printf "%s" "${1}" | tr -d '/' | grep -o '..' | wc -l)
while [ "${i}" != "${directories_to_walk}" ];
do
if [ $(pwd) = '/' ]; then
return;
fi
cd ../
i=$((i+1))
done
;;
esac
}
This runs perfectly, and in fact is POSIX compliant so you can use it in any POSIX shell, there is one issue I can't fix however. I do not want to have to type
I just want to be able to type
I know being able to do this will depend on the shell (I am using yash), but I cannot find how to set this for the life of me. Does anybody know?
Last edited by FossilizedDaemon; 06-09-2024 at 11:27 PM.
Reason: Forget a period ;-;
|
|
|
06-09-2024, 11:01 PM
|
#2
|
Senior Member
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,924
|
As a start:
Code:
- while [ i != "${directories_to_walk}" ];
+ while [ x"$i" != x"$directories_to_walk" ];
|
|
|
06-09-2024, 11:15 PM
|
#3
|
LQ Newbie
Registered: Jun 2023
Posts: 18
Original Poster
Rep:
|
Quote:
Originally Posted by NevemTeve
As a start:
Code:
- while [ i != "${directories_to_walk}" ];
+ while [ x"$i" != x"$directories_to_walk" ];
|
While I understand what the removal of the braces does I do not understand what the x does.
|
|
|
06-10-2024, 01:30 AM
|
#4
|
Senior Member
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,924
|
Some versions of test(1) might get confused if your variables contain unusual values like '', '-a', '!=' etc; prepending an 'x' solves this. Nonetheless the important point here is using "$i" instead of i
|
|
|
06-10-2024, 02:14 AM
|
#5
|
LQ Addict
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702
|
I don't really understand, a simple cd $1 would do the job I think, without while, grep and whatnot.
That code is extremely inefficient, running that directories_to_walk= line for every directory is terrible. But anyway, if it works you can use it.
|
|
1 members found this post helpful.
|
06-10-2024, 09:23 AM
|
#6
|
LQ Newbie
Registered: Jun 2023
Posts: 18
Original Poster
Rep:
|
Quote:
Originally Posted by pan64
I don't really understand, a simple cd $1 would do the job I think, without while, grep and whatnot.
That code is extremely inefficient, running that directories_to_walk= line for every directory is terrible. But anyway, if it works you can use it.
|
You could do it that way, but then you would have to adhere to the cd syntax which this lets you avoid doing for easier spamming when you want to walk back a lot. I won't say it's a good habit to form, but it's one I have and this is the solution to it.
|
|
|
06-10-2024, 09:24 AM
|
#7
|
LQ Newbie
Registered: Jun 2023
Posts: 18
Original Poster
Rep:
|
Quote:
Originally Posted by NevemTeve
Some versions of test(1) might get confused if your variables contain unusual values like '', '-a', '!=' etc; prepending an 'x' solves this. Nonetheless the important point here is using "$i" instead of i
|
Gotcha.
|
|
|
06-10-2024, 09:31 AM
|
#8
|
LQ Addict
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702
|
Quote:
Originally Posted by FossilizedDaemon
You could do it that way, but then you would have to adhere to the cd syntax which this lets you avoid doing for easier spamming when you want to walk back a lot. I won't say it's a good habit to form, but it's one I have and this is the solution to it.
|
I don't understand it. Can you show some examples?
|
|
|
06-10-2024, 10:32 AM
|
#9
|
Senior Member
Registered: Feb 2007
Location: UK
Distribution: Debian
Posts: 3,708
|
This is a dubious idea to start with, but that implementation is stupidly over-convoluted.
Since Yash claims to have command-not-found functionality, read its documentation to discover how that functions and then all it should take is simple logic equivalent to...
Code:
if "$MISSING_COMMAND" matches '^(\.\./)+$' then cd "$MISSING_COMMAND"
As for that "x" stuff, you can safely ignore it - it is NOT needed for POSIX-compliant shells, which Yash claims to be. (It was a workaround for bugs in old shells.)
|
|
|
06-10-2024, 11:22 AM
|
#10
|
LQ Newbie
Registered: Jun 2023
Posts: 18
Original Poster
Rep:
|
Quote:
Originally Posted by boughtonp
This is a dubious idea to start with, but that implementation is stupidly over-convoluted.
Since Yash claims to have command-not-found functionality, read its documentation to discover how that functions and then all it should take is simple logic equivalent to...
Code:
if "$MISSING_COMMAND" matches '^(\.\./)+$' then cd "$MISSING_COMMAND"
As for that "x" stuff, you can safely ignore it - it is NOT needed for POSIX-compliant shells, which Yash claims to be. (It was a workaround for bugs in old shells.)
|
I have been reading over their documentation and added the command-not-found part, but keep running into issues where when I give ../ or .. it says command-not-found or this is a directory and does nothing. My Yash specific code looks like this
Code:
_walk() {
case "${1}" in
..*)
i=0
directories_to_walk=$(printf "%s" "${1}" | tr -d '/' | grep -o '..' | wc -l)
while [ "${i}" != "${directories_to_walk}" ];
do
if [ "$(pwd)" = '/' ]; then
return;
else
cd ../
i=$((i+1))
fi
done
HANDLED=true
;;
esac
}
COMMAND_NOT_FOUND_HANDLER=("${COMMAND_NOT_FOUND_HANDLER}" '_walk "${@}"')
As for the logic you gave, it wouldn't work exactly how I like this to work (i.e. where '..', '../', '.......', '../.../.../...../' all are valid ways of using it). The documentation you linked on the 'x' stuff is very interesting, thank you! I had no idea older shells needed that work around.
EDIT:
Aha! It was an issue somewhere else in my configuration. I got it to work now, thank you
Last edited by FossilizedDaemon; 06-10-2024 at 11:25 AM.
|
|
|
06-10-2024, 11:29 AM
|
#11
|
LQ Addict
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702
|
That is still utterly overcomplicated
remove every './' from the input string, count the remaining number of dots and cd .. that many times. And do nothing if there are other chars inside.
checking / is not really required, because .. is defined in the root dir too.
|
|
|
06-10-2024, 12:37 PM
|
#12
|
LQ Newbie
Registered: Jun 2023
Posts: 18
Original Poster
Rep:
|
Quote:
Originally Posted by pan64
That is still utterly overcomplicated
remove every './' from the input string, count the remaining number of dots and cd .. that many times. And do nothing if there are other chars inside.
checking / is not really required, because .. is defined in the root dir too.
|
While I would love to improve my code, I am a little confused here. From my understanding I am counting how dots there and cding that many times. Do you mean outside of a loop? I don't really know how I would do that, don't I need something to keep track of how many times I have already cded? As for the '/' check, I do this because otherwise my AUTO_AFTER_CD stuff will get run even when it cd ../ in root and I will get a bunch of ls output for root.
|
|
|
06-10-2024, 01:57 PM
|
#13
|
LQ Addict
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702
|
Code:
_walk() {
waste=$(printf "%s" "${1}" | sed 's#[./]*##g') # if it is not empty there is something "else" in $1
dots=$(printf "%s" "${1}" | sed 's#\./##g') # just remove every ./ (what to do if we have // in it?) - sed s!//*!/!g will remove it
for (number of . in dots -1) # which is the length of dots -1 (but you can add / to the initial string, in that case -1 is not needed)
cd ..
}
I meant something like this. But it is not tested.
|
|
|
06-10-2024, 02:41 PM
|
#14
|
LQ Newbie
Registered: Jun 2023
Posts: 18
Original Poster
Rep:
|
Quote:
Originally Posted by pan64
Code:
_walk() {
waste=$(printf "%s" "${1}" | sed 's#[./]*##g') # if it is not empty there is something "else" in $1
dots=$(printf "%s" "${1}" | sed 's#\./##g') # just remove every ./ (what to do if we have // in it?) - sed s!//*!/!g will remove it
for (number of . in dots -1) # which is the length of dots -1 (but you can add / to the initial string, in that case -1 is not needed)
cd ..
}
I meant something like this. But it is not tested.
|
Ahhh, this is the difference. The for loop arithmetic method is not POSIX compliant so it wouldn't work for me. The sed statement is useful, but aside from that this wouldn't work for me. Thank you though
|
|
|
06-11-2024, 12:31 AM
|
#15
|
LQ Addict
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702
|
obviously you need to make it work for yourself if you wish. It is not a for loop but a pseudo code which is only used to explain the algorithm. Or probably better to say, it is just an idea.
|
|
|
All times are GMT -5. The time now is 01:15 PM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|