bash script - return full path and filename
I'm attempting to improve a bash script, ReMove to Waste. It moves files into ~/.Waste and prepends the present working directory to the destination folder under ~/.Waste.
I'd like to have it moved to the same path from where the file or folder originate. For instance, if I'm in my home directory, and delete a file within it called "temp," it will move it to ~/.Waste/home/andy/temp So that is indeed where the file is supposed to go, but it's basing it on my PWD at the time. I'd like to return the full path of the file name. But whatever PWD I'm in, the best I can get is "./temp" basename and dirname are the opposite of what I need. I tried ${FILE%} but that also returns "./temp" I've been googling for over an hour, but getting nowhere. Thanks, in advance. |
Use $PWD as a prefix to the file name.
--------------------- Steve Stites |
I'd like to be able to move the file into ~/.Waste/original/path
Using $PWD doesn't guarantee that. I need to have the absolute path of the file returned. (a few minutes later) Found it. Bash equivalent for PHP realpath() |
Wow ... That's something new I learnt today. Thanks for pointing me to the article - http://andy.wordpress.com/2008/05/09...-php-realpath/
:) Linux Archive |
Quote:
|
Code:
source="./tmp/myfile" |
Linux console recycle bin
Disillusionist, thanks, but unfortunately, I don't know what your code does. Regular expressions confuse me greatly (though I'm now starting to realize how useful sed can be and that I need to learn how to use it), and I saw PWD in there; using the present working directory was something I was trying to avoid.
Here's the script so far, for anyone interested. The -u option will undo the last operation performed. This is the version currently in the subversion repo at http://sourceforge.net/projects/rmw I won't be doing anything more with it for a few weeks or month, but if anyone has any suggestions for improvements, I'll most likely implement them at some point. Code:
#!/bin/sh |
Quote:
The important part of the code I suggested, passed the value of $source through two sed statements.: Code:
echo $source|sed "s@^./@$PWD@"|sed "s@^/@@" The second sed statement removes the leading / character |
Quote:
I'm still using $PWD for symlinks. I'm using 'readlink' to determine absolute paths, and it always returns the source of the symlink, which I don't want. |
The sed statement would only use PWD where the source file begins with ./
Any files that begin with ./ are by definition starting from the current working directory. EDIT: Your script (downloaded from sourceforge) needs to run as #!/bin/bash on my machine (although I suspect this is the same on others) as source is a shell builtin for bash, but doesn't appear to be for traditional bourne shell. -- I am using Jaunty (Ubuntu 9.04) |
Thanks, I made the change and issued a new file release (made some other changes too).
On Slackware, which is my primary system, /bin/sh is a symlink to /bin/bash. |
Try this (where $file is e.g. ./temp):
Code:
echo "$( readlink -f "$( dirname "$file" )" )/$( basename "$file" )" |
Quote:
It would also be nice to see an uninstall.sh file to simplify removal. EDIT: As rm is linked to rmw, you need rmw to cater for all the options that rm can use, especially rm -rf |
Quote:
(say, move2waste.sh) that is in your $PATH, perhaps in /usr/local/bin, and when you move2waste.sh some_file where some_file is in a certain directory /some/path you want some_file to be moved to /some/path/.Waste (provided you have the right permissions in /some/path) I would go like that (I'll skip the permissions verifications, the number of arguments, etc.) #!/bin/sh # here you loop for each argument entered, # verifying that the file exists, etc. # say the file to be processed is in $filename # $filename is a basename (no preceding directories: # you invoke the script in the directory where # you want to move files) CWD=$PWD # create .Waste directory if it doesn't already exist mkdir -p $CWD/.Waste mv $filename $CWD/.Waste ################################## if you want to invoke the script move2waste.sh with arguments such as /absolute/path/to/filename or relativepath/to/filename you should, when you process these arguments, retrieve the the part before the filename (e.g., argument=/some/path/filename p=${argument%/*}) then figure out if it's a relative or absolute path: if it starts with '/' it's absolute, otherwise relative ('.', '[a-zA-Z0-9]', ...) if it's absolute you set CWD to that: CWD=$p if it's relative: if it starts with './' you remove that (p=$(echo $p | sed 's?^\./??'), if it starts with '../', you get the name of the directory above ... then you set CWD to $CWD/$p |
I've been using readlink for a few months now, so I'm no longer in need of methods to use absolute paths.
Quote:
I issued another release, and included the install-sh file which 'configure' requires. I also edited it, and the configure script to change #!/bin/sh to #!/bin/bash I added support for the -rf option. It'll be a while before I add support for all the other other options 'rm' has. I'm recovering from some pain issues which limits the amount of time I'm able to spend at the computer. Know of any good speech recog programs? :) As for an uninstall.sh, I don't know how to do that while accounting for what users might set for a prefix install dir using 'configure'. The install-sh file is just copied from my automake directory when I create the Makefile.in. For a workaround, I added more information to the INSTALL file about where files are being copied to. I also added an UNINSTALL file with more instructions. Additionally, I created a .deb package and an .rpm package while logged into my Kubuntu 9.04 partition and those two files are available for download on the sourceforge project page. I used checkinstall to create the packages. Thanks for all your suggestions. |
a little modification
Quote:
a little modifiation :) Code:
source="./tmp/myfile" |
Quote:
|
Quote:
ta0kira has it right: to return the absolute path of a filename that is originally given with a relative path: for example you are at a bash prompt in /dir1/dir2/dir3/dir4 and the file is /dir1/dir2/file1 ABSOLUTE_DIR=$(dirname $(readlink -f ../../dir2/file1)) |
A solution I found elsewhere...
|
Another solution is to use the external pwd command instead of the bash builtin. In the following illustration /home/c/Templates is a symlink to /home/c/d/Templates
Code:
c@CW9:~$ ls -l Templates |
I didn't know readlink was nonstandard. Thanks to the suggestions, this is what I've come up with.
Code:
#!/bin/bash |
I like this better:
Code:
#!/bin/bash |
I made another change. In the previous function I posted, it has to be called three times if the absolute path, absolute path with filename, and base filename are required. That can slow things down. This method may be slightly more memory intensive, but speeds up the process.
Code:
function gfp_info() { |
It could go a little faster if:
pwd does not return the absolute path if the path was reached via a symlink in which case pwd -P is needed: Code:
c@CW8:~$ cd /tmp |
Quote:
|
I've made the changes to my script, with some exceptions.
cd "-" &>/dev/null And when I was using rmw on a file in my present working directory, RP=${FILE%/*} would kick out an error. (No slash to find) Thanks for the suggestions, catkin. Good stuff. |
Quote:
Code:
c@CW8:/tmp$ FILE=foo |
I was wrong about the slash, but the code you suggested assigns the basename, whereas I want everything except for the basename. Since I'm not good at explaining, allow me to illustrate:
Code:
# extracts the directory component of the full path FILE: temp /home/andy/bin/rmw: line 451: cd: temp: Not a directory DC: "temp" pwd: - "/home/andy/Documents" `temp' -> `/home/andy/.Waste/files/temp.2011-01-26h13m11s43' --- Code:
# extracts the directory component of the full path FILE: temp DC: "" pwd: - "/home/andy/Documents" `temp' -> `/home/andy/.Waste/files/temp.2011-01-26h13m14s23' I've added an if clause around cd $DC Code:
if [ $DC ]; then |
For the basename: basename=${fullpath##*/}. It looks like this at the command prompt:
Code:
c@CW8:/tmp$ fullpath=/etc/rsyncd.conf |
Code:
function gfp_info() { |
Yes even another code for absolute path
How about this one to get absolute path? Simpler, even local variables are not needed. Little modification will get you the file base name if needed, as soon as you can define its behaviour when you give directory as argument (should it be the last directory or empty string?).
Code:
function abspath { |
you can try mine as well:
Code:
function getabspath { Code:
getabspath "/path/.././././to/somewhere/" the function can also be modified to accept another argument which could represent the name of the variable which will hold the result. i.e. like Code:
getabspath <path> <variable_name> |
Calling a binary from a bash script can sometimes be preferred. Here's some C code which can be compiled using gcc -Wall -o getpath getpath.c
Code:
// getpath.c |
Thanks for the script!
The script from arifsaha was without doubt leaps and bounds better than any of the others; clean, simple and cross-platform compatible. Works just as well on BSD as on GNU based toolsets. I will try to give credit whenever I use it - which I suspect will be plenty more than the three applications so far :-)
Quote:
|
just one comment: instead basename and dirname you can use parameter substitution:
Code:
${var##*/} # <== basename _____________________________________ If someone helps you, or you approve of what's posted, click the "Add to Reputation" button, on the left of the post. Happy with solution ... mark as SOLVED (located in the "thread tools") |
Readability
I mentioned clean and simple; for the uninitiated, that looks like voodo :study: I prefer verbosity over terseness if the terseness comes with a reduction in readability.
|
actually it is not really so simple: using parameter substitution will be processed inside the shell, using basename and dirname will fork another task, will open pipe therefore it costs more, much more. If you were familiar with bash enough you should not speak about readability problems in such cases....
|
Thanks for the info
Quote:
|
Quote:
|
Check out my full post about getting absolute pathnames in all general shells and also for a binary format.
http://www.linuxquestions.org/questi...-scripts-3956/ |
The realpath command was added to coreutils, as of version 8.15, I believe. Not the best solution yet -- not all *nix distros have it installed yet, and I couldn't say anything about Macs.
See also: GNU core utilities |
Quote:
|
Parameter substitution not working?
I just tried the suggestions from pan64, but I was unable to make it work. Can anyone change the script above and make it work with parameter substitution? I have also searched the man page for bash on the "var##" pattern, and I cannot find anything referencing it.
Quote:
|
please open a new thread and specify your problem, or at least show us what you tried:
Code:
$ var=/a/v/b/n/f/e |
I wonder how my script could not provide the one you require that you have to go all the troubles.
|
All times are GMT -5. The time now is 05:08 PM. |