You are not logged in.
Since I moved a lot of my stuff onto a separate "data" partition, symlinked from my /home/john folder I discovered the Crunchbang Openbox "places" menu doesn't follow symlinks, despite its claims to do so. Apostrophes in path names also cause trouble. Had a look at the code but found it was perl, so to try and tweak it would require learning perl first...
So I put together this bash (now dash) version. On my system at least, it seems to follow symlinks OK, and handles filenames with breaks, quotes or "&"s in them. As a bonus, you can set it to open executables in a text editor instead of executing them, likewise .desktop files, and add any other special conditions you want to overrule the default action which is set by Thunar (or pcmanfm or ... ). It's possible to have some dotfiles/dotfolders visible if you want. Usage is exactly the same as the default Crunchbang /usr/bin/crunchbang/obpipemenu-places script (it's in ~/.config/openbox/pipemenus in Statler I think), so the easiest way to install it might be to rename the old file and replace it with this:
EDIT: The latest version will always be in the pastebin, so you no longer need to scroll down the thread, unless you're interested in the bugs that came up...
EDIT: You now have the option of adding a "recently opened files" submenu at the top of the places menu if you want. Make sure you have the recently_opened_menu.sh script, add its path to the places script in the place shown in the comments, and edit the entry in menu.xml to add the --recent option:
<menu id="places" label="Places" execute="/path/to/dash_places_menu.sh --recent ~/" />EDIT 2012/12/17: The comments have been edited: Openbox 3.5 needs the user's home directory to be written as '~/' not '~'. Also the default text editor set to geany instead of gedit.
EDIT 2012/06/19: Small tweak to double any underbars in the filename label, so Openbox displays them normally. Otherwise they are used as keyboard shortcuts.
EDIT 2012/10/05 Bugfix.
Now works on bash as well as dash. Essential for anyone who has changed their default system shell to bash!
------------------------------------------------------------------------------------
(This version is old - use the pastebin link above.)
#!/bin/bash
# bash places menu for openbox
#### Usage: add
# <menu id="places" label="Places" execute="/path/to/bash_places_menu.sh ~" />
# to your .config/openbox/menu.xml (you don't need a final slash after the ~)
# Default command to open files or folders with
open_cmd=thunar
# Your favourite text editor
text_editor=gedit
# function to overrule default open command for certain files - add other conditions to choice
open_file_cmd() {
[[ -x $1 ]] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit executables instead of executing
#[ -x "$1" ] && { echo "terminator -e"; return; } # uncomment this and comment out previous line to run executables in terminal instead of editing
[[ $1 = *.desktop ]] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit .desktop files instead of executing
echo "$open_cmd" # default open command
}
path="${1:-$HOME}" # default place is ~/
escape() { # escape xml special characters
string="${1//&/&}"
string="${string//</<}"
string="${string//>/>}"
string="${string//\"/"}"
string="${string//\'/'}"
echo "$string" ;
}
pathe="$( escape "$path" )"
echo "<openbox_pipe_menu>
<item label=\"Browse here..\">
<action name=\"Execute\">
<execute>
$open_cmd \"$pathe\"
</execute>
</action>
</item>
<separator />"
shopt -s nullglob #dotglob # uncomment "dotglob" to see dot files/folders, here & "shopt" line below
for i in "$path"/*
do
ie="$( escape "$i" )"
shortname="${ie##*/}"
[[ -d $i ]] && { echo "<menu id=\"$ie"\ label=\"$shortname\" execute=\""$0" "$ie"\" />"; continue; }
echo "<item label=\"$shortname\">
<action name=\"Execute\">
<execute>
$(open_file_cmd "$i") \"$ie\"
</execute>
</action>
</item>"
done
shopt -u nullglob #dotglob
echo "</openbox_pipe_menu>"
exit(edit: 7/22 Unquoted the commands on lines 34 & 49 so commands like 'terminator -e" will work.)
(edit: 8/13 Cleaned up quotes a bit.)
The hardest part was escaping and quoting, which cost me a couple of fun-filled hours, but now it seems to be working OK. Please give it a try and post if you find any bugs, or have ideas for improvements. 
Last edited by johnraff (2012-10-05 05:48:50)
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
Thank you, I would really like that, as I also use separate partition 
Offline
Another example: if you want to run executables in a terminal instead of editing them, change line 13 to
[[ -x $1 ]] && { echo "terminator -e"; return; } The cool thing about using bash is it's so hackable. 
Last edited by johnraff (2010-08-02 12:19:33)
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
Great thank you, I was using a very difficult way with one .sh for each folder I wanted to browse:
For example, in my Ob menu, I create a pipe menu for each folder I wanted to access!!
#!/usr/bin/perl
# Recursively browse filesystem through openbox3 pipe menus
#### Usage: add
# <menu id="browse" label="Browse" execute="obpipemenu-places ~" />
# to your .config/openbox/menu.xml
#### CAVEAT ####
# This script was hacked on exclusively in stints between the hours of
# 4 and 5 in the morning. Quality may have suffered.
####
# Script by dircha from ob list on 05/17/04
# suggested improvements by John Russell on 05/17/04 implemented
# a year later by Kacper Wysocki.
# 05/30/05 - Kacper Wysocki
# - opens files with 'rox', which launches appropriate file handler
# - hidden directories now stay hidden
# - spaces, ampersands in dir- and filenames are escaped
# - newlines at each entry to make output a little readable
# 06/04/05 - Kacper Wysocki
# - use $0 for scriptname
# - use $ENV{'HOME'} as default path
# - now follows symlinks
use strict;
# Command to lauch files with
my $cmd = "thunar";
my $path = $ARGV[0];
$path = "/media/données2/share_spy/Sort_out" if $path eq "";
my @files = split /\n/, `ls -1p '$path'`;
mk_menu_element($path, @files);
sub mk_menu_element {
my ($path, @files) = @_;
print "<openbox_pipe_menu>\n";
# "Browse here..." lauches this dir
print "<item label=\"Browse here..\">".
"\n\t<action name=\"Execute\">".
"\n\t\t<execute>$cmd '$path'</execute>".
"\n\t</action>".
"\n</item>\n".
"<separator />";
foreach $_ (@files) {
my $length = length $_;
my $last_c = substr $_, $length - 1, 1;
if ($last_c eq "/") {
print mk_dir_element($path, substr $_, 0, $length - 1);
} elsif ($last_c eq "@") {
print mk_sym_element($path, substr $_, 0, $length - 1);
} else {
print mk_file_element($path, $_);
}
}
print "</openbox_pipe_menu>\n";
}
sub mk_dir_element {
my ($path, $name) = @_;
# escape ampersand and space in pathnames
$path =~ s/&/&/g;
$name =~ s/&/&/g;
$path =~ s/ /\\ /g;
$name =~ s/ /\\ /g;
return "<menu id=\"$path/$name\" label=\"$name\" execute=\"$0 $path/$name\" />\n";
}
sub mk_sym_element {
my ($path, $name) = @_;
# escape ampersand in pathnames
$path =~ s/&/&/g;
$name =~ s/&/&/g;
# Follow symlinks instead of opening links in rox.
return "<menu id=\"$path/$name\" label=\"$name\" execute=\"$0 $path/$name\" />\n";
=cut
return "<item label=\"$name\">".
"\n\t<action name=\"Execute\">".
"\n\t\t<execute>$cmd '$path/$name'</execute>".
"\n\t</action>"
. "\n</item>\n";
=cut
}
sub mk_file_element {
my ($path, $name) = @_;
my $label = $name;
# escape ampersand in pathnames
$path =~ s/&/&/g;
$name =~ s/&/&/g;
return "<item label=\"$name\">".
"\n\t<action name=\"Execute\">".
"\n\t\t<execute>$cmd '$path/$name'</execute>".
"\n\t</action>"
. "\n</item>\n";
}I'm not so good to understand code but with your I will manage to do things better!!
Thanks:D
Offline
A slight modification - this version does not figure out the right "open" command for each file as it writes the menu, but sets the menu entry to call the script again with the "--open" option, so the "open_file_cmd()" function only has to be run once, when the entry is actually clicked. This seems to be slightly faster, though not as dramatic an improvement as I hoped. 
The original Crunchbang obpipemenu-places script is slightly faster again in some situations, and much faster in others. Whether or not this makes a difference in practice you'll have to try and see. On my box the speed difference between the perl and bash scripts is not noticable, so for me it's worth using the bash script to get executables, symlinks and "difficult" file names coped with.
#!/bin/bash
# bash places menu for openbox
#### Usage: add
# <menu id="places" label="Places" execute="/path/to/bash_places_menu.sh ~" />
# to your .config/openbox/menu.xml
# Default command to open files or folders with
open_cmd=thunar
# Text editor
text_editor=gedit
open_file_cmd() { # function to overrule default open command for certain files - add other conditions to choice
[[ -x $1 ]] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit executables instead of executing
#[[ -x $1 ]] && { echo "terminator -e"; return; } # uncomment this and comment out previous line to run executables in terminal instead of editing
[[ $1 = *.desktop ]] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit .desktop files instead of executing
echo "$open_cmd" # default open command
}
path="${1:-$HOME}" # default starting place is ~/, otherwise $1
[[ $1 = '--open' ]] && {
exec $(open_file_cmd "$2") "$2"
exit # "exit" should be unnecessary in fact
}
escape() { # escape xml special characters
#string="s/\&/\&/g;s/</\</g;s/>/\>/g;s/\"/\"/g;s/'/\'/g;"
#sed "$string" <<<"$1"
string="${1//&/&}" # this seems to be faster than sed
string="${string//</<}"
string="${string//>/>}"
string="${string//\"/"}"
string="${string//\'/'}"
echo "$string" ;
}
pathe="$( escape "$path" )"
echo "<openbox_pipe_menu>
<item label=\"Browse here..\">
<action name=\"Execute\">
<execute>
$open_cmd \"$pathe\"
</execute>
</action>
</item>
<separator />"
shopt -s nullglob #dotglob # uncomment "dotglob" to see dot files/folders, here & "shopt" line below
for i in "$path"/*
do
ie="$( escape "$i" )"
shortname="${ie##*/}"
[[ -d $i ]] && { echo "<menu id=\"$ie\" label=\"$shortname\" execute=\""$0" "$ie"\" />"; continue; }
echo "<item label=\"$shortname\">
<action name=\"Execute\">
<execute>
\"$0\" --open \"$ie\"
</execute>
</action>
</item>"
done
shopt -u nullglob #dotglob
echo "</openbox_pipe_menu>"
exit(edit: 8/13 Cleaned up quotes a bit.)
Any suggestions for making this faster ( other than learning python or perl
) would be appreciated though.
Last edited by johnraff (2010-08-12 17:38:44)
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
have you tried using /bin/sh (dash) rather than bash, that should result in a decent speedup.
there may be a few things you may need to change ie shopt isn't in dash afaik, although ls with different flags should get you the same results.
- - - - - - - - Wiki Pages - - - - - - -
#! install guide *autostart programs, modify the menu & keybindings
configuring Conky *installing scripts
Offline
Thanks benj1 that was a good idea. Dash seems about twice as fast as bash running the same script - but yes I did have to change a few things:
*) Replaced conditions [[ ... ]] with [ ... ] and quoted the variables inside. No problem
*) I used the "nullglob" option with bash to avoid having mysterious "*" items in empty directories. On dash I replaced it with [ "$(ls -A "$path")" ] && ... to avoid parsing empty directories. Nullglob's slightly faster but no big deal.
*) The big one was in the "escape()" function to make content xml-safe - not being able to use bash's built-in substring replacement (${variable//substring/replacement}) meant using sed instead which is much slower. My guess is that it's because you're calling an outside programme, but the result was that the dash version of the script ended up being twice as slow as the bash version! Just a minute though - that "escape" function is being run on every item, and maybe 99% of the time it's unnecessary. How about checking first if the string contains any characters needing escaping ( & < > " ' ) and only running sed if it's really needed? You can do it with 'case' and that's all it took to get the time right down. 
Here's the current "final" version (edit now incorporating benj1's 100819 bugfix):
#!/bin/sh
# shell (hopefully dash!) places menu for openbox
#### Usage: add
# <menu id="places" label="Places" execute="/path/to/dash_places_menu.sh ~" />
# to your .config/openbox/menu.xml (you don't need a final slash after the ~)
# Default command to open files or folders with - others might be pcmanfm, gnome-open...
default_open_cmd=thunar
# Text editor of choice
text_editor=gedit
# extra dotfiles to display in HOME folder (dotfiles are hidden by default)
# edit the list (space separated) or comment this line out, to taste:
shown_dotfiles='.config .Xdefaults .bash_aliases .bashrc .fonts.conf .gtkrc-2.0.mine .profile'
# function to overrule default open command for certain files - add other conditions to choice
open_file_cmd() {
[ -x "$1" ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit executables instead of executing
#[ -x "$1" ] && { echo "terminator -e"; return; } # uncomment this and comment out previous line to run executables in terminal instead of editing
[ "$1" = *.desktop ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit .desktop files instead of executing
echo "$default_open_cmd" # default open command
}
#######################################################################
[ "$1" = '--open' ] && {
exec $(open_file_cmd "$2") "$2"
exit # "exit" should be unnecessary in fact
}
path="${1:-$HOME}" # default starting place is ~/, otherwise $1
[ -d "$path" ] || { echo "$path is not a directory"; exit 1; }
# escape xml special characters
escape() {
case "$1" in # only escape if string needs it
*\&*|*\<*|*\>*|*\"*|*\'*) :;;
*) echo "$1"; return;;
esac
string="s/\&/\&/g;s/</\</g;s/>/\>/g;s/\"/\"/g;s/'/\'/g;"
echo "$1" | sed "$string"
}
pathe="$( escape "$path" )"
echo "<openbox_pipe_menu>
<item label=\"Browse here..\">
<action name=\"Execute\">
<execute>
$default_open_cmd \"$pathe\"
</execute>
</action>
</item>
<separator />"
[ "$(ls -A "$path")" ] && { # only run this for non-empty directories
unset extra_entries
[ "$path" = "$HOME" ] && extra_entries="$shown_dotfiles"
for i in "$path"/* $extra_entries
do
shortname="$( escape "${i##*/}" )"
ie="${pathe}/${shortname}"
[ -d "$i" ] && { echo "<menu id=\"$ie\" label=\"$shortname\" execute=\""$0" "$ie"\" />"; continue; }
echo "<item label=\"$shortname\">
<action name=\"Execute\">
<execute>
\"$0\" --open \"$ie\"
</execute>
</action>
</item>"
done
}
echo "</openbox_pipe_menu>"
exitThis now parses a folder with 20 subfolders in 15ms on my box, compared with 12ms for obpipemenu-places, which seems close enough to me, considering you've got some advantages:
*) Symlinked folders are followed properly.
*) Apostrophes and other tricky characters are escaped properly: any filenames, including those with spaces, should be OK.
*) More options: you can choose to edit scripts instead of running them, or run them in a terminal, or add any other conditions (open files in a certain directory with a certain command... , do something different with files newer than... )
*) You can display certain selected dotfiles or dotfolders in your home directory if you want. ( I display .config, .profile and a couple of others )
*) It's a shell script so easily tweakable by many Crunchbang users.
Last edited by johnraff (2010-08-20 04:46:41)
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
glad to be of help, is 15ms quick enough now of are you looking to shave off a few more miliseconds ? 
ive found the same as you, dash does tend to be alot faster if you stick to its functions, but you tend to lose some of that advantage calling extra bits and bobs.
- - - - - - - - Wiki Pages - - - - - - -
#! install guide *autostart programs, modify the menu & keybindings
configuring Conky *installing scripts
Offline
^no I think 15ms will do to be going on with - considering I've got my openbox submenuShowDelay set to 200 anyway! 
Hoping this will now be fast enough for people with processors slower than my 2.8GHz Pentium 4 
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
just got round to installing this, I have to say it seems to be slightly quicker than places.pl, although time doesn't seem to support that, anyway good job, but I found a bug
pathe="$( escape "$path" )"
echo "<openbox_pipe_menu>
<item label=\"Browse here..\">
<action name=\"Execute\">
<execute>
$default_open_cmd \"$pathe\"
</execute>
</action>
</item>
<separator />"
#!/bin/sh
# shell (hopefully dash!) places menu for openbox
#### Usage: add
# <menu id="places" label="Places" execute="/path/to/dash_places_menu.sh ~" />
# to your .config/openbox/menu.xml (you don't need a final slash after the ~)
# Default command to open files or folders with - others might be pcmanfm, gnome-open...
default_open_cmd=thunar
# Text editor of choice
text_editor=gedit
# extra dotfiles to display in HOME folder (dotfiles are hidden by default)
# edit the list (space separated) or comment this line out, to taste:
shown_dotfiles='.config .Xdefaults .bash_aliases .bashrc .fonts.conf .gtkrc-2.0.mine .profile'
# function to overrule default open command for certain files - add other conditions to choice
open_file_cmd() {
[ -x "$1" ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit executables instead of executing
#[ -x "$1" ] && { echo "terminator -e"; return; } # uncomment this and comment out previous line to run executables in terminal instead of editing
[ "$1" = *.desktop ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit .desktop files instead of executing
echo "$default_open_cmd" # default open command
}
#######################################################################
[ "$1" = '--open' ] && {
exec $(open_file_cmd "$2") "$2"
exit # "exit" should be unnecessary in fact
}
path="${1:-$HOME}" # default starting place is ~/, otherwise $1
[ -d "$path" ] || { echo "$path is not a directory"; exit 1; }
# escape xml special characters
escape() {
case "$1" in # only escape if string needs it
*\&*|*\<*|*\>*|*\"*|*\'*) :;;
*) echo "$1"; return;;
esac
string="s/\&/\&/g;s/</\</g;s/>/\>/g;s/\"/\"/g;s/'/\'/g;"
echo "$1" | sed "$string"
}
pathe="$( escape "$path" )"
echo "<openbox_pipe_menu>
<item label=\"Browse here..\">
<action name=\"Execute\">
<execute>
$default_open_cmd \"$pathe\"
</execute>
</action>
</item>
<separator />"
[ "$(ls -A "$path")" ] && { # only run this for non-empty directories
unset extra_entries
[ "$path" = "$HOME" ] && extra_entries="$shown_dotfiles"
for i in "$path"/* $extra_entries
do
shortname="$( escape "${i##*/}" )"
ie="${pathe}/${shortname}"
[ -d "$i" ] && { echo "<menu id=\"$ie\" label=\"$shortname\" execute=\""$0" "$ie"\" />"; continue; }
echo "<item label=\"$shortname\">
<action name=\"Execute\">
<execute>
\"$0\" --open \"$ie\"
</execute>
</action>
</item>"
done
}
echo "</openbox_pipe_menu>"
exit- - - - - - - - Wiki Pages - - - - - - -
#! install guide *autostart programs, modify the menu & keybindings
configuring Conky *installing scripts
Offline
Hi benj1 thanks for trying it out.
OK that $default_open_cmd - it's the default (
) command to open anything - I assumed it would be a file manager (thunar in my case), so a reasonable choice for opening a folder, since this code is for the "browse here" bit at the top of the menu, or sub-menu.
Are you suggesting it would be a better choice to use $(open_file_cmd "$path"), so giving the user more freedom to tweak?
Or have I overlooked something else? (that happens a lot
)
Last edited by johnraff (2010-08-19 04:27:54)
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
you overlooked that, that was the corrected version 
your most recent version had:
pathe="$( escape "$path" )"
echo "<openbox_pipe_menu>
<item label=\"Browse here..\">
<action name=\"Execute\">
<execute>
$open_cmd \"$pathe\"
</execute>
</action>
</item>
<separator />"$open_cmd is empty, so it doesn't do anything, so I corrected it, and posted a patched script for anyone else that wanted it.
I'm assuming you want thunar/'a filemanager' to open here, that would seem to be the expected functionality.
- - - - - - - - Wiki Pages - - - - - - -
#! install guide *autostart programs, modify the menu & keybindings
configuring Conky *installing scripts
Offline
glurk... OK that was what I overlooked.
My local script has the same bug so I must have forgotten to test the "Browse here..." bit.
Cheers for picking it up - script now edited. 
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
Made a couple of minor modifications:
* it no longer matters whether the path is sent with a trailing slash or not
* added .local to the default list of dotfiles to display
* expanded comments slightly, and trimmed formatting slightly
From now on I'll put the latest version in the pastebin: see the first post.
Last edited by johnraff (2010-10-23 05:02:34)
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
1: Can i suggest some minor visual improvements ? :
#!/bin/sh
# shell (hopefully dash!) places menu for openbox
#### Usage: add
# <menu id="places" label="Places" execute="/path/to/dash_places_menu.sh ~" />
# to your .config/openbox/menu.xml (you don't need a final slash after the ~)
# Default command to open files or folders with - others might be pcmanfm, gnome-open...
default_open_cmd=thunar
# Text editor of choice
text_editor=gedit
# extra dotfiles to display in HOME folder (dotfiles are hidden by default)
# edit the list (space separated) or comment this line out, to taste:
shown_dotfiles='.config .local .Xdefaults .bash_aliases .bashrc .fonts.conf .gtkrc-2.0.mine .profile'
# function to overrule default open command for certain files - add other conditions to choice
open_file_cmd() {
[ -x "$1" ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit executables instead of executing
#[ -x "$1" ] && { echo "terminator -e"; return; } # uncomment this and comment out previous line to run executables in terminal instead of editing
[ "$1" = *.desktop ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit .desktop files instead of executing
echo "$default_open_cmd" # use default open command if above conditions not satisfied
}
#######################################################################
# if "--open" argument is sent as $1, open file ($2) instead of generating menu
[ "$1" = '--open' ] && {
exec $(open_file_cmd "$2") "$2"
exit # "exit" should be unnecessary in fact
}
path="${1:-$HOME}" # default starting place is ~, otherwise $1
path="${path%/}" # remove any final slash
[ -d "$path" ] || { echo "$path is not a directory"; exit 1; }
# escape xml special characters
escape() {
case "$1" in # only escape if string needs it
*\&*|*\<*|*\>*|*\"*|*\'*) :;;
*) echo "$1"; return;;
esac
string="s/\&/\&/g;s/</\</g;s/>/\>/g;s/\"/\"/g;s/'/\'/g;"
echo "$1" | sed "$string"
}
pathe="$( escape "$path" )"
echo "<openbox_pipe_menu>
<separator label=\"This Directory\"/>
<item label=\"Browse here..\">
<action name=\"Execute\">
<execute>
$default_open_cmd \"$pathe\"
</execute>
</action>
</item>
<separator label=\"contains\"/>"
[ "$(ls -A "$path")" ] && { # only parse the folder if it's not empty
unset extra_entries
[ "$path" = "$HOME" ] && extra_entries="$shown_dotfiles"
for i in "$path"/* $extra_entries
do
shortname="$( escape "${i##*/}" )"
ie="${pathe}/${shortname}"
[ -d "$i" ] && { echo "<menu id=\"$ie\" label=\"$shortname\" execute=\""$0" "$ie"\" />"; continue; }
echo "<item label=\"$shortname\">
<action name=\"Execute\">
<execute>
\"$0\" --open \"$ie\"
</execute>
</action>
</item>"
done
}
echo "</openbox_pipe_menu>"
exit2: Is there a way to open the root directory ( / ) ?
( if / is passed as argument - invalid output from pipemenu )
3: Is there a way to display the directories before files ?
just lille the commands :
ls -X
or
ls --group-directories-first
(
i tried to change the line [ "$(ls -A "$path")" ] to
[ "$(ls -X -A "$path")" ] and
[ "$(ls --group-directories-first -A "$path")" ]
without sucess
)
Offline
Hi Divakarsd, thanks for your input!
1) I guess this was the added line
<separator label=\"This Directory\"/> ?
I'll try putting it in and see how I like it... 
2) Yes, that's a bug, because I've removed the trailing slash from the supplied $path, to avoid double slashes. I'll try and do it another way. Thanks for catching it!
3) Not sure about this. It comes from the shell's preferred way of listing things. (I noticed when switching from Bash to Dash the displayed order changed.)
The [ "$(ls -A "$path")" ] part is just a test to see if the directory has anything in it before displaying its contents, otherwise you'd get a "*" for empty directories. It's nothing to do with the display order.
This is where the items get listed up:
for i in "$path"/* $extra_entries
...
ie the shell lines up the items in $path/* in whatever order it likes, then does $extra_entries. Maybe it's possible to do the directories first - I'll have a think... (anyone else?)
cheers 
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
if you change
[ "$path" = "$HOME" ] && extra_entries="$shown_dotfiles"
for i in "$path"/* $extra_entries
doto
[ "$path" = "$HOME" ] && extra_entries="$shown_dotfiles"
patha=$(ls -d --group-directories-first "$path"/*)
for i in $patha $extra_entries
dothat should work
a perhaps better way would be instead of
[ "$(ls -A "$path")" ] && { # only run this for non-empty directories
unset extra_entries
[ "$path" = "$HOME" ] && extra_entries="$shown_dotfiles"
for i in "$path"/* $extra_entries
dodoing ...
patha=$(ls -d --group-directories-first "$path"/*)
[ "$patha" ] && { # only run this for non-empty directories
unset extra_entries
[ "$path" = "$HOME" ] && extra_entries="$shown_dotfiles"
for i in $patha $extra_entries
doto avoid an extra call to 'ls'.
- - - - - - - - Wiki Pages - - - - - - -
#! install guide *autostart programs, modify the menu & keybindings
configuring Conky *installing scripts
Offline
1) Bug :
couldn`t you just use :
sed 's/\/\//\//g'
to get rid of doubble slashes ?
Example:
echo "//home/to//path/..." | sed 's/\/\//\//g'
#result : "/home/to/path/..."
2) Benj1 great work !
changes included in my version
3) Visual appearance :
shows the path you are currently in
meant to be used with 4)
echo "<openbox_pipe_menu>
<item label=\"Browse here..\">
<action name=\"Execute\">
<execute>
$default_open_cmd \"$pathe\"
</execute>
</action>
</item>
<separator />"to
echo "<openbox_pipe_menu>
<separator label=\"$path\"/>
<item label=\"Browse here..\">
<action name=\"Execute\">
<execute>
$default_open_cmd \"$pathe\"
</execute>
</action>
</item>"4) Added Separator for Files and Directories
<separator label=\"Directories\"/>
directories listened here.....
<separator label=\"Files\"/>
files listened here.....
change :
for i in $patha $extra_entries
do
shortname="$( escape "${i##*/}" )"
ie="${pathe}/${shortname}"
[ -d "$i" ] && { echo "<menu id=\"$ie\" label=\"$shortname\" execute=\""$0" "$ie"\" />"; continue; }
echo "<item label=\"$shortname\">>to
dir=0 #says witch filetype was encountered last to add separator: 0=nothing, 1=directory, 2=file
for i in $patha $extra_entries
do
if [ $dir -eq 0 ] && [ -d "$i" ];then
echo "<separator label=\"Directories\"/>"
dir=1
fi
if [ $dir -lt 2 ] && [ -f "$i" ];then
echo "<separator label=\"Files\"/>"
dir=2
fi
shortname="$( escape "${i##*/}" )"
ie="${pathe}/${shortname}"
[ -d "$i" ] && { echo "<menu id=\"$ie\" label=\"$shortname\" execute=\""$0" "$ie"\" />"; continue; }
echo "<item label=\"$shortname\">Entire Code :
#!/bin/sh
# shell (hopefully dash!) places menu for openbox
#### Usage: add
# <menu id="places" label="Places" execute="/path/to/dash_places_menu.sh ~" />
# to your .config/openbox/menu.xml (you don't need a final slash after the ~)
# Default command to open files or folders with - others might be pcmanfm, gnome-open...
default_open_cmd=thunar
# Text editor of choice
text_editor=gedit
# extra dotfiles to display in HOME folder (dotfiles are hidden by default)
# edit the list (space separated) or comment this line out, to taste:
shown_dotfiles='.config .bashrc'
# function to overrule default open command for certain files - add other conditions to choice
open_file_cmd() {
[ -x "$1" ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit executables instead of executing
#[ -x "$1" ] && { echo "terminator -e"; return; } # uncomment this and comment out previous line to run executables in terminal instead of editing
[ "$1" = *.desktop ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit .desktop files instead of executing
echo "$default_open_cmd" # use default open command if above conditions not satisfied
}
#######################################################################
# if "--open" argument is sent as $1, open file ($2) instead of generating menu
[ "$1" = '--open' ] && {
exec $(open_file_cmd "$2") "$2"
exit # "exit" should be unnecessary in fact
}
path="${1:-$HOME}" # default starting place is ~, otherwise $1
path="${path%/}" # remove any final slash
[ -d "$path" ] || { echo "$path is not a directory"; exit 1; }
# escape xml special characters
escape() {
case "$1" in # only escape if string needs it
*\&*|*\<*|*\>*|*\"*|*\'*) :;;
*) echo "$1"; return;;
esac
string="s/\&/\&/g;s/</\</g;s/>/\>/g;s/\"/\"/g;s/'/\'/g;"
echo "$1" | sed "$string"
}
pathe="$( escape "$path" )"
echo "<openbox_pipe_menu>
<separator label=\"$path\"/>
<item label=\"Browse here..\">
<action name=\"Execute\">
<execute>
$default_open_cmd \"$pathe\"
</execute>
</action>
</item>"
patha=$(ls -d --group-directories-first "$path"/*)
[ "$patha" ] && { # only run this for non-empty directories
unset extra_entries
[ "$path" = "$HOME" ] && extra_entries="$shown_dotfiles"
dir=0 #says witch filetype was encountered last to add separator: 0=nothing, 1=directory, 2=file
for i in $patha $extra_entries
do
if [ $dir -eq 0 ] && [ -d "$i" ];then
echo "<separator label=\"Directories\"/>"
dir=1
fi
if [ $dir -lt 2 ] && [ -f "$i" ];then
echo "<separator label=\"Files\"/>"
dir=2
fi
shortname="$( escape "${i##*/}" )"
ie="${pathe}/${shortname}"
[ -d "$i" ] && { echo "<menu id=\"$ie\" label=\"$shortname\" execute=\""$0" "$ie"\" />"; continue; }
echo "<item label=\"$shortname\">
<action name=\"Execute\">
<execute>
\"$0\" --open \"$ie\"
</execute>
</action>
</item>"
done
}
echo "</openbox_pipe_menu>"
exitOffline
Thanks both!
@benj1 The problem with using ls to make a list of files is filenames with breaks:
john@raffles3:~$ touch 'an empty file'
john@raffles3:~$ patha=$(ls -d --group-directories-first ~/* )
john@raffles3:~$ for i in $patha ; do echo $i ; done
...
/home/john/bin
/home/john/an
empty
file
/home/john/backup
/home/john/documents
...Also backup and documents are symlinks to directories so don't get listed with the other directories, but after the file 'an empty file'.
I was thinking of doing this by running a loop twice, once to sort into directories and files, then to process the two lists. The first loop is pretty lightweight so hopefully shouldn't add too much time(?) Putting directories and files into two arrays, like this:
john@raffles3:~$ unset directories
john@raffles3:~$ unset files
john@raffles3:~$ for i in ~/* ; do [ -d "$i" ] && { directories=( "${directories[@]}" "$i" ); continue; }; files=( "${files[@]}" "$i" ); done
john@raffles3:~$ for i in "${directories[@]}" "${files[@]}"; do echo "$i"; done
/home/john/backup
/home/john/bin
/home/john/Desktop
/home/john/documents
...
/home/john/wallpaper
/home/john/an empty file
/home/john/testdisk1.log
/home/john/testdisk.log'an empty file' stays together, and 'backup' and 'documents' join the other directories.
...but unfortunately Dash doesn't support arrays 
@Divakarsd Sed would work for that too, but I hit on 'tr' to squash together any number of slashes into one:
path="$( echo "$path"/ | tr -s '/' )"so there's just one slash at the end of the path. (tr might be slightly faster than sed.) Then I'll tweak the rest of the script to deal with paths with final slashes.
3) & 4) look quite doable. I think just running the "for" loop separately for the directories and files arrays, and echoing the separator in between should do it. 
If I hit a way round that array thing in Dash (or just go back to Bash
) I'll try and get a candidate new version together in the next day or so incorporating your ideas.
Cheers!
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
Ah - it wasn't that hard after all, no need for arrays, or ls either.
In the main loop that runs through all the contents of $path/, each item is already being tested to see if it's a directory or not so as to send out the right menu code. So, at that point, instead of echoing the code right away, add it to the end of variables directories_menu or files_menu respectively.
[ -d "$i" ] && { directories_menu="$directories_menu
<menu id=\"$ie\" label=... />"; continue; }
files_menu="$files_menu
<item label=...
</item>"Then echo the two variables at the end, with the separators in between.
[ -n "$directories_menu" ] && echo "<separator label=\"Directories\" />
$directories_menu"
[ -n "$files_menu" ] && echo "<separator label=\"Files\" />
$files_menu"It seems to be working OK at this end 
"time" shows it being a bare couple of milliseconds slower, though for some reason subjectively I seem to notice just a bit more lag than before - nothing terrible though. As always YMMV. Here's the current whole thing:
#!/bin/sh
# shell (hopefully dash!) places menu for openbox
#### Usage: add
# <menu id="places" label="Places" execute="/path/to/dash_places_menu.sh ~" />
# to your .config/openbox/menu.xml (you don't need a final slash after the ~)
# Default command to open files or folders with - others might be pcmanfm, gnome-open...
default_open_cmd=thunar
# Text editor of choice
text_editor=gedit
# extra dotfiles to display in HOME folder (dotfiles are hidden by default)
# edit the list (space separated) or comment this line out, to taste:
shown_dotfiles='.config .local .Xdefaults .bash_aliases .bashrc .fonts.conf .gtkrc-2.0.mine .profile .xsession-errors'
# function to overrule default open command for certain files - add other conditions to choice
open_file_cmd() {
[ -x "$1" ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit executables instead of executing
#[ -x "$1" ] && { echo "terminator -e"; return; } # uncomment this and comment out previous line to run executables in terminal instead of editing
[ "$1" = *.desktop ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit .desktop files instead of executing
echo "$default_open_cmd" # use default open command if above conditions not satisfied
}
#######################################################################
# if "--open" argument is sent as $1, open file ($2) instead of generating menu
[ "$1" = '--open' ] && {
exec $(open_file_cmd "$2") "$2"
exit # "exit" should be unnecessary in fact
}
path="${1:-$HOME}" # default starting place is ~, otherwise $1
path="$( echo ${path}/ | tr -s '/' )" # ensure one final slash
[ -d "$path" ] || { echo "$path is not a directory"; exit 1; }
# escape xml special characters
escape() {
case "$1" in # only escape if string needs it
*\&*|*\<*|*\>*|*\"*|*\'*) :;;
*) echo "$1"; return;;
esac
string="s/\&/\&/g;s/</\</g;s/>/\>/g;s/\"/\"/g;s/'/\'/g;"
echo "$1" | sed "$string"
}
pathe="$( escape "$path" )"
echo "<openbox_pipe_menu>
<separator label=\"$pathe\" />
<item label=\"Browse here..\">
<action name=\"Execute\">
<execute>
$default_open_cmd \"$pathe\"
</execute>
</action>
</item>
<separator />"
[ "$(ls -A "$path")" ] && { # only parse the folder if it's not empty
unset extra_entries directories_menu files_menu
[ "$path" = "$HOME"/ ] && extra_entries="$shown_dotfiles"
for i in "$path"* $extra_entries
do
shortname="$( escape "${i##*/}" )"
ie="${pathe}${shortname}"
[ -d "$i" ] && { directories_menu="$directories_menu
<menu id=\"$ie\" label=\"$shortname\" execute=\""$0" "$ie"\" />"; continue; }
files_menu="$files_menu
<item label=\"$shortname\">
<action name=\"Execute\">
<execute>
\"$0\" --open \"$ie\"
</execute>
</action>
</item>"
done
}
[ -n "$directories_menu" ] && {
# comment out next line if you don't want "Directories" label
echo "<separator label=\"Directories\" />"
echo "$directories_menu"; }
[ -n "$files_menu" ] && {
# comment out next line if you don't want "Files" label
echo "<separator label=\"Files\" />"
echo "$files_menu"; }
echo "</openbox_pipe_menu>"
exitLast edited by johnraff (2010-10-21 05:44:25)
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
@benj1 The problem with using ls to make a list of files is filenames with breaks:
ls -Q 
as for symlinks, theres
ls -X
but I don't think that differentiates between symlinks to files and directories tho
I think the idea of using ls might want revisiting, youve got just about every formatting option you could hope for in there, without having to add it along with processing overhead into the script.
this script could do whats needed whilst being more easily modifiable by others
ls -dXQ --group-directories-first "$path"/* | awk 'BEGIN{print "Directories"; a=0}{ if ( system("[ -f "$1" ] ") == 0 && a == 0){print "Files"; a=1}; print $1}'where as some people may just want
ls -dQ "$path"/* others may want
ls -AFQ "$path"/* i know its not realy a problem at the moment but it could rapidly get complicated if you add a few more options
- - - - - - - - Wiki Pages - - - - - - -
#! install guide *autostart programs, modify the menu & keybindings
configuring Conky *installing scripts
Offline
I think the idea of using ls might want revisiting, youve got just about every formatting option you could hope for in there, without having to add it along with processing overhead into the script.
I was put off using ls in scripts after reading this diatribe. 
Still, we are calling ls anyway to test the directory for non-emptiness so you do have a point there I guess.
this script could do whats needed whilst being more easily modifiable by others
ls -dXQ --group-directories-first "$path"/* | awk 'BEGIN{print "Directories"; a=0}{ if ( system("[ -f "$1" ] ") == 0 && a == 0){print "Files"; a=1}; print $1}'
Yes, that works nicely in a terminal, but let's not forget this script is to build an openbox menu, with clickable entries, so just printing out the words doesn't do it - we need all the other code wrapped round it.
My feeling now is that since the files have to be tested if they're a directory or not anyway, in order to build the right kind of menu item, we might as well use that information at that point to append the code to the $directories_menu or $files_menu variables, then echo those variables. I don't think it's adding much work to the script.
As to the sort order - that would indeed be more flexible using ls. Dash (unlike Bash I think) uses the standard C order, and doesn't seem to take any notice of environment variables like LC_COLLATE or LC_CTYPE which I thought for a moment might be a way to tweak it. Personally, I'll just live with the default C sort order...
Anyway, the above new version of the script does seem to be doing the job OK - directories first, with labelled separators. It looks quite nice with the dark Statler Openbox theme. 
(I'm in two minds whether I actually want those files/directories separators as they take up space, but they're easy enough to comment out.)
( btw, just found this reference on moving from Bash to Dash:
https://wiki.ubuntu.com/DashAsBinSh )
Last edited by johnraff (2010-10-21 15:44:57)
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
Thanks for the script. I wanted to be able to open the s-links since I found #!. There is one problem though. Everything that is inside a s-linked directory is opened with gedit. ex: png file inside normal forlder is opened with the proper viewer (trough thunar), but inside a s-link is opened with gedit (or terminal if I have choosen to execute instead of editing executable files).
I took the code from the pastebin.
EDIT: Actually I noticed that only images are opened with the proper program. everything else, s-link folder or not, is opened with gedit.
Last edited by slapfish (2010-10-21 12:46:03)
Offline
@slapfish that's strange - everything works fine for me ???
The only thing I can think of is that if a file is executable it is opened in gedit instead of executing it, which is what Thunar would do. (You've kept the 'default_open_cmd=thunar' line?)
You haven't got a lot of executable .png files have you?
I'll upload the latest version to the pastebin soon, but it shouldn't make any difference anyway...
John
--------------------
( a boring Japan blog , and idle twitterings )
Offline
I "debug" it a little and I found out that if I leave uncommented only the line about default opening:
# function to overrule default open command for certain files - add other conditions to choice
open_file_cmd() {
#[ -x "$1" ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit executables instead of executing
#[ -x "$1" ] && { echo "terminator -e"; return; } # uncomment this and comment out previous line to run executables in terminal instead of editing
#[ "$1" = *.desktop ] && { echo "$text_editor"; return; } # comment out this line if you don't want to edit .desktop files instead of executing
echo "$default_open_cmd" # use default open command if above conditions not satisfied
}it works perfectly. so I wonder if I have to have something installed that I don't...
Offline
Copyright © 2012 CrunchBang Linux.
Proudly powered by Debian. Hosted by Linode.
Debian is a registered trademark of Software in the Public Interest, Inc.