LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
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


Reply
  Search this Thread
Old 06-09-2024, 10:35 PM   #1
FossilizedDaemon
LQ Newbie
 
Registered: Jun 2023
Posts: 18
Blog Entries: 1

Rep: Reputation: 1
Question Walking Up Directories For Every ..


Hello,

I am currently trying to implement a basic shell function that will
Code:
cd ../
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
Code:
walk ../../
I just want to be able to type
Code:
../../
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 ;-;
 
Old 06-09-2024, 11:01 PM   #2
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,924
Blog Entries: 1

Rep: Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886
As a start:
Code:
- while [ i != "${directories_to_walk}" ];
+ while [ x"$i" != x"$directories_to_walk" ];
 
Old 06-09-2024, 11:15 PM   #3
FossilizedDaemon
LQ Newbie
 
Registered: Jun 2023
Posts: 18

Original Poster
Blog Entries: 1

Rep: Reputation: 1
Quote:
Originally Posted by NevemTeve View Post
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.
 
Old 06-10-2024, 01:30 AM   #4
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,924
Blog Entries: 1

Rep: Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886
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
 
Old 06-10-2024, 02:14 AM   #5
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702

Rep: Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535
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.
Old 06-10-2024, 09:23 AM   #6
FossilizedDaemon
LQ Newbie
 
Registered: Jun 2023
Posts: 18

Original Poster
Blog Entries: 1

Rep: Reputation: 1
Quote:
Originally Posted by pan64 View Post
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.
 
Old 06-10-2024, 09:24 AM   #7
FossilizedDaemon
LQ Newbie
 
Registered: Jun 2023
Posts: 18

Original Poster
Blog Entries: 1

Rep: Reputation: 1
Quote:
Originally Posted by NevemTeve View Post
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.
 
Old 06-10-2024, 09:31 AM   #8
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702

Rep: Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535
Quote:
Originally Posted by FossilizedDaemon View Post
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?
 
Old 06-10-2024, 10:32 AM   #9
boughtonp
Senior Member
 
Registered: Feb 2007
Location: UK
Distribution: Debian
Posts: 3,708

Rep: Reputation: 2627Reputation: 2627Reputation: 2627Reputation: 2627Reputation: 2627Reputation: 2627Reputation: 2627Reputation: 2627Reputation: 2627Reputation: 2627Reputation: 2627

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.)

 
Old 06-10-2024, 11:22 AM   #10
FossilizedDaemon
LQ Newbie
 
Registered: Jun 2023
Posts: 18

Original Poster
Blog Entries: 1

Rep: Reputation: 1
Smile

Quote:
Originally Posted by boughtonp View Post
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.
 
Old 06-10-2024, 11:29 AM   #11
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702

Rep: Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535
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.
 
Old 06-10-2024, 12:37 PM   #12
FossilizedDaemon
LQ Newbie
 
Registered: Jun 2023
Posts: 18

Original Poster
Blog Entries: 1

Rep: Reputation: 1
Quote:
Originally Posted by pan64 View Post
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.
 
Old 06-10-2024, 01:57 PM   #13
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702

Rep: Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535
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.
 
Old 06-10-2024, 02:41 PM   #14
FossilizedDaemon
LQ Newbie
 
Registered: Jun 2023
Posts: 18

Original Poster
Blog Entries: 1

Rep: Reputation: 1
Talking

Quote:
Originally Posted by pan64 View Post
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
 
Old 06-11-2024, 12:31 AM   #15
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702

Rep: Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535
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.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
"Walking" icons in KDE eddiep Mandriva 4 05-11-2006 01:18 PM
LXer: Kevin Carmony: Walking The Line of a Divided Community LXer Syndicated Linux News 1 05-09-2006 01:19 PM
SUSE 10 CD1 Boot Screen shows Walking Penguins, WTF AvatarofVirgo SUSE / openSUSE 3 11-10-2005 05:37 PM
KDE Panel moves to center of screen after walking away for 10 mins... Whitehat Linux - General 2 04-30-2003 07:24 PM
Walking a newbie through installing Linux hux Linux - General 2 01-18-2003 12:43 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:15 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration