- Using both basename and full path in find -exec
- 5 Answers 5
- Get Absolute File Path in Linux
- Use readlink to get file path
- Use realpath to get full file path
- Use the find command to get the absolute file path
- Print full path with the ls command
- Conclusion
- Print full path of files and sizes with find in Linux
- 3 Answers 3
Using both basename and full path in find -exec
I’m having an adventure in the world of bash scripting with find today. Say I’m looking to copy any png file in any subdirectory of /home/mine/Pictures to /home/mine/pngcoppies and rename it «copy[basename]»using find and -exec. This would require me to use both the full path name and the basename in the same exec command. My problem is that I don’t know how to get the basename. (See below)
find /home/mine -iname "*.png" -exec cp <> /home/mine/pngcoppies/copy \;
Note: The above isn’t actually what I’m doing, but it’s a fundamental example of the issue, so a workaround using some other method to achieve the same ends wouldn’t really apply here. The question is fundamentally about find -exec and its use of basenames. Thanks in advance!
5 Answers 5
To see what is going on when you execute the find, just type set -xv
-x : Prints commands and their arguments as they are executed.
-v : Prints shell input lines as they are read.
set -xv find . -name "*.xml" -exec echo <> \;
find . -name "*.xml" -exec echo <> \; + find . -name '*.xml' -exec echo '<>' ';' ./log.xml ./svnLog.xml
And then find execute echo passing the found filename instead of the litteral : ‘<>‘
but when you add something to the <> like below :
find . -name "*.xml" -exec echo something<> \; + find . -name '*.xml' -exec echo 'something<>' ';' something<> something<>
Here the echo is executed twice for the 2 xml files that I have and since there is no more ‘<>‘ is the parameter list of the exec, it is not going to be replaced. so we got the echo ‘something<>‘ for each file found.
To deal with this, you can think about executing echo passing to it the filename as parameter like for example :
sh -xvc 'echo sothing/$0' filename
We already know what is -x and -v . -c is to get the command from the string after it ( man sh )
sh -xvc 'echo somthing/$0' filename + sh -xvc 'echo somthing/$0' filename echo somthing/$0 + echo somthing/filename sothing/filename
I used ‘ echo somthing/$0 ‘ between ‘ ‘ so that $0 don’t get expanded by the current shell. try it with » » and you will see the expantion of $0 😉
So to get back to your ‘problem’, the find should be formatted as below:
find . -name "*.xml" -exec sh -xvc 'echo sothing/$0' <> \;
find . -name "*.xml" -exec sh -xvc 'echo sothing/$0' <> \; + find . -name '*.xml' -exec sh -xvc 'echo sothing/$0' '<>' ';' echo sothing/$0 + echo sothing/./log.xml sothing/./log.xml echo sothing/$0 + echo sothing/./svnLog.xml sothing/./svnLog.xml
As we can see know, the find is going to execute the shell cammand echo sothing/$0 passing to it ‘<>‘ (replaced by the filename found by find) so we get the desired echo sothing/./log.xml
set +xv to remove the verbose mode and we can get :
find . -name "*.xml" -exec sh -c 'echo "cp $0 someWhereElse/$0"' <> \; cp ./log.xml someWhereElse/./log.xml cp ./svnLog.xml someWhereElse/./svnLog.xml
so in your case , you have just to execute the copy in a sub shell (add sh or bash or you favorit shell after the exec) and let find pass the filename as parapeter to the it 😉
find /home/mine -iname "*.png" -exec sh -c 'cp $0 /home/mine/pngcoppies/copy/$0' <> \;
Hope this can help, and execuse me for my English.
Get Absolute File Path in Linux
Here are different ways to get the absolute file paths in Linux command line.
You can get the full path of a directory with the pwd command:
But how do you get the absolute path of a file in Linux?
There are several ways to print the full path of files:
- readlink
- realpath
- find
- combining ls and pwd
Let me show you these commands one by one. But before that, I suggest brushing up on the basics of the absolute and relative path concept first.
Use readlink to get file path
The purpose of the readlink command is to resolve symbolic links. You can use it to display the full path of a file like this:
[email protected]:~$ readlink -f sample.txt /home/abhishek/sample.txt [email protected]:
Use realpath to get full file path
The realpath command is used for resolving the absolute file names. Among other uses, it can show the full path to a file.
Take a look at this example:
[email protected]:~$ realpath sample.txt /home/abhishek/sample.txt [email protected]:~$
If you use it with a symbolic link, it will show the real path of the original file. You can force it to not follow the symbolic link:
Here’s an example where it showed the full path to the source file by default and then I forced it to show the symbolic link, not its original file.
[email protected]:~$ realpath linking-park /home/abhishek/Documents/ubuntu-commands.md [email protected]:~$ realpath -s linking-park
Use the find command to get the absolute file path
Here’s the thing with the find command. Everything is relative to the directory you give it for search location.
If you give it . it will show the relative path. If you give it the absolute path of the directory, you’ll get the absolute path of the files you are searching for.
Use the command substitution with the find command like this:
You can run it to find the full path of a single file:
[email protected]:~$ find $(pwd) -name sample.txt /home/abhishek/sample.txt
Or, you can use it with a bunch of files matching a certain pattern:
[email protected]:~/Documents/eBooks$ find $(pwd) -name "*.pdf" /home/abhishek/Documents/eBooks/think-like-a-programmer.pdf /home/abhishek/Documents/eBooks/linux-guide.pdf /home/abhishek/Documents/eBooks/absolute-open-bsd.pdf /home/abhishek/Documents/eBooks/theory-of-fun-for-game-design.pdf /home/abhishek/Documents/eBooks/Ubuntu 1804 english.pdf /home/abhishek/Documents/eBooks/computer_science_distilled_v1.4.pdf /home/abhishek/Documents/eBooks/the-art-of-debugging-with-gdb-and-eclipse.pdf
Print full path with the ls command
Now this one is a bit tricky and messy.
You can use the environment variable PWD with ls command like this to display the files and directories with their absolute path:
You get an output like this:
[email protected]:~/test$ ls -ld $PWD/* -r--rw-r-- 1 abhishek abhishek 0 Jul 27 16:57 /home/abhishek/test/file2.txt drwxrwxr-x 2 abhishek abhishek 4096 Aug 22 16:58 /home/abhishek/test/new
However, to print the full path of a file with the ls command, you’ll have to use it like this:
Not the cleanest solution but it works.
[email protected]:~$ ls -l $PWD/sample.txt -rw-r--r-- 1 abhishek abhishek 12813 Sep 7 11:50 /home/abhishek/sample.txt [email protected]:~$
Conclusion
I showed four different ways to get the full file path in Linux. The find and ls commands are common while realpath and readlink are hardly known to many Linux users. It’s always good to learn new things, isn’t it?
Print full path of files and sizes with find in Linux
Here are the specs: Find all files in / modified after the modification time of /tmp/test, exclude /proc and /sys from the search, and print the full path of the file along with human readable size. Here is what I have so far:
find / \( -path /proc -o -path /sys \) -prune -o -newer /tmp/test -exec ls -lh <> \; | less
The issue is that the full path doesn’t get printed. Unfortunately, ls doesn’t support printing the full path! And all solutions I have found that show how to print the full path suggest using find. 😐 Any ideas? Thanks!
3 Answers 3
Instead of -exec ls -lh <> \; you can also use the printf option:
find / \( -path /proc -o -path /sys \) -prune -o -newer /tmp/test -printf "%s %p\n" | less
Although that will just print the size in bytes and not in the nice human-readable format ls supports.
find / \( -path /proc -o -path /sys \) -prune -o -newer /tmp/test -exec ls -lhd <> \; | less
That will also fix the problem you were bound to have with files showing up twice in your list.
I too enjoy my fullpaths, so I’ve ended up creating few aliases just for such an occasion: alias ldf=’ls $PWD/* -dF’ alias lfp=’ls $PWD/* -daFc —group-directories-first’ alias lfh=’ls $PWD/.* -daFc —group-directories-first’ alias lafp=’ls $PWD/.* $PWD/* -daFc —group-directories-first’ And just simply store ’em to $HOME/.bashrc (these already follow the syntax of .bashrc) Though, if one wants to copy+paste the code to terminal (Not a recommended practice, but I’m not your guardian, so:) Here is a direct paste for .bashrc:
echo » alias ldf=’ls $PWD/* -dF’ alias lfp=’ls $PWD/* -daFc —group-directories-first’ alias lfh=’ls $PWD/.* -daFc —group-directories-first’ alias lafp=’ls $PWD/.* $PWD/* -daFc —group-directories-first'» >> ~/.bashrc
All of these are basically for the same goal, with minor tweaks for specific purposes; like: ldf=List Directorys Files, lfp= List Full Path -organizing flag used, lfh= List Full Hidden, And last; for all the users and porpoises: lafp = List All-Full Path(both hidden and regulars)