409

I am writing a shell script that takes file paths as input.

For this reason, I need to generate recursive file listings with full paths. For example, the file bar has the path:

/home/ken/foo/bar

but, as far as I can see, both ls and find only give relative path listings:

./foo/bar   (from the folder ken)

It seems like an obvious requirement, but I can't see anything in the find or ls man pages.

How can I generate a list of files in the shell including their absolute paths?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Ken
  • 77,016
  • 30
  • 84
  • 101

28 Answers28

400

If you give find an absolute path to start with, it will print absolute paths. For instance, to find all .htaccess files in the current directory:

find "$(pwd)" -name .htaccess

or if your shell expands $PWD to the current directory:

find "$PWD" -name .htaccess

find simply prepends the path it was given to a relative path to the file from that path.

Greg Hewgill also suggested using pwd -P if you want to resolve symlinks in your current directory.

Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222
  • 11
    Note that if you also want to resolve symlinks, use `pwd -P`. – Greg Hewgill Oct 29 '08 at 09:28
  • 7
    This is helpful, but I think user431529's response below is more valid: `ls -d -1 $PWD/**/*` but I guess `find $PWD` also works (tested in bash) – Brian Apr 27 '11 at 16:47
  • 11
    @Brian Why? `find $PWD` is simple. The `ls` incantation is complex and unwieldy (unless you alias it). `find` is not dependent on shell glob expansions, so will work in any shell. `find` is also a lot more flexible, I can get a recursive listing of all files, or perhaps of all directories, or maybe I want a listing of all xml files, or all files changed in the last week. All that is possible with `find`, but not easily with `ls`. – Matthew Scharley Jul 08 '11 at 07:31
  • 13
    I had to use `find "\`pwd\`" -name .htaccess` because of spaces in directory names – Paulo Casaretto Apr 16 '12 at 17:47
  • I don't get it, this command does not give me the absolute path of the file I, while other answers down on the list does the job. – Bjørn Otto Vasbotten Sep 13 '12 at 09:09
  • Running a Debian/Turnkey Linux that i login to by putty, and using the exact command mentioned above. It returns the relative link to the file. – Bjørn Otto Vasbotten Sep 13 '12 at 10:36
  • @Bjørn: Copy/paste? What does `pwd` output? I used it as an example, but as long as you give `find` an absolute path it should output absolute paths. – Matthew Scharley Sep 13 '12 at 11:09
  • for me, I need `*.htaccess` to get all `.htaccess` files. (bash > 4) – jimh Jun 15 '20 at 05:56
249
readlink -f filename 

gives the full absolute path. But if the file is a symlink, you'll get the final resolved name.

Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
balki
  • 26,394
  • 30
  • 105
  • 151
  • 9
    Nice. Does not work on the BSD Variant of readlink (i.e Mac).I use gnucoreutils on mac. And hence can use greadlink which works with the above solution. – sheki Aug 17 '11 at 10:29
  • 3
    @AndrewLazarus - For Mac OS X, use `realpath` instead – c z Sep 24 '19 at 10:42
  • if you install bash tools via `brew install coreutils`, then the executable will be installed as `/usr/local/opt/coreutils/libexec/gnubin/readlink` – redolent Oct 23 '19 at 09:18
172

Use this for dirs (the / after ** is needed in bash to limit it to directories):

ls -d -1 "$PWD/"**/

this for files and directories directly under the current directory, whose names contain a .:

ls -d -1 "$PWD/"*.*

this for everything:

ls -d -1 "$PWD/"**/*

Taken from here http://www.zsh.org/mla/users/2002/msg00033.html

In bash, ** is recursive if you enable shopt -s globstar.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
user431529
  • 2,222
  • 1
  • 17
  • 16
  • 2
    ls -d -1 $PWD/**/* does not recurse. Wish I could take my +1 back. You can do ** for each depth you need to go though. – user606723 Aug 23 '11 at 04:59
  • 7
    The ** operator is a recursive globbing operator. If you use the command in a shell that supports it (such as zsh), it will work properly. – zebediah49 Sep 02 '11 at 19:18
  • ls -d1 "$PWD/"{\*,.\*} to also catch the hidden (dot) files. For me the recursive version in the answer didn't prepend the absolute path to files in subfolders. – Zael Aug 09 '19 at 12:04
  • I think I'll have to use find... I get -> bash: /bin/ls: Argument list too long – TelamonAegisthus May 08 '20 at 03:38
  • ls -altd ../{path}/**/* is my preference when recursing on all subdirs – randyslavage Aug 19 '22 at 20:58
52

You can use

find $PWD 

in bash

Vinko Vrsalovic
  • 330,807
  • 53
  • 334
  • 373
  • 6
    That will give the path of the current directory, and all the files and directories below it, as well. That's probably not what people are looking for. – Bill Apr 16 '13 at 18:55
37
ls -d "$PWD/"*

This looks only in the current directory. It quotes "$PWD" in case it contains spaces.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
didi
  • 725
  • 6
  • 10
  • This is still a very valid answer, but it would be good to include the info that this does not work recursively (which is what I was looking for in fact!) – bbbco Nov 25 '13 at 20:45
  • 3
    For recursive use: find . -exec ls -ld $PWD/{} \; – Learner Dec 05 '13 at 04:53
16

Command: ls -1 -d "$PWD/"*

This will give the absolute paths of the file like below.

[root@kubenode1 ssl]# ls -1 -d "$PWD/"*
/etc/kubernetes/folder/file-test-config.txt
/etc/kubernetes/folder/file-test.txt
/etc/kubernetes/folder/file-client.txt
GSM
  • 356
  • 4
  • 11
13

You can do

ls -1 | xargs realpath

If you need to specify an absolute path or relative path, you can do that as well

ls -1 $FILEPATH | xargs realpath
Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
Jabir Ali
  • 568
  • 6
  • 11
12

Try this:

find "$PWD"/

You get list of absolute paths in working directory.

Koder95
  • 121
  • 1
  • 6
10

The $PWD is a good option by Matthew above. If you want find to only print files then you can also add the -type f option to search only normal files. Other options are "d" for directories only etc. So in your case it would be (if i want to search only for files with .c ext):

find $PWD -type f -name "*.c" 

or if you want all files:

find $PWD -type f

Note: You can't make an alias for the above command, because $PWD gets auto-completed to your home directory when the alias is being set by bash.

edorian
  • 38,542
  • 15
  • 125
  • 143
Gurpreet
  • 762
  • 1
  • 7
  • 9
  • Actually, -d doesn't mean only directories - it means it treats directories like files. So if you ls -d /home, you'll get back "/home", not a listing of what's in /home. – Travis Mar 04 '12 at 21:40
  • @Travis: he was talking about the option to find, not ls. In his case "find / -type d" would find only directories - as he said. – oligofren Jun 18 '12 at 17:04
8

If you give the find command an absolute path, it will spit the results out with an absolute path. So, from the Ken directory if you were to type:

find /home/ken/foo/ -name bar -print    

(instead of the relative path find . -name bar -print)

You should get:

/home/ken/foo/bar

Therefore, if you want an ls -l and have it return the absolute path, you can just tell the find command to execute an ls -l on whatever it finds.

find /home/ken/foo -name bar -exec ls -l {} ;\ 

NOTE: There is a space between {} and ;

You'll get something like this:

-rw-r--r--   1 ken admin       181 Jan 27 15:49 /home/ken/foo/bar

If you aren't sure where the file is, you can always change the search location. As long as the search path starts with "/", you will get an absolute path in return. If you are searching a location (like /) where you are going to get a lot of permission denied errors, then I would recommend redirecting standard error so you can actually see the find results:

find / -name bar -exec ls -l {} ;\ 2> /dev/null

(2> is the syntax for the Borne and Bash shells, but will not work with the C shell. It may work in other shells too, but I only know for sure that it works in Bourne and Bash).

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Trudius
  • 81
  • 1
  • 1
  • 2
    You can pass multiple args to the same `ls` process with `-exec ls -ld {} +`. (You probably want `-d` to not have `ls` list directory contents). Or better, use find's built-in `ls` with `find ... name bar -ls`. Also, you have the syntax wrong for one arg per command: you have to quote the semicolon from the shell, so it's `{} \;`. – Peter Cordes Feb 10 '19 at 08:58
6

Just an alternative to

ls -d "$PWD/"* 

to pinpoint that * is shell expansion, so

echo "$PWD/"*

would do the same (the drawback you cannot use -1 to separate by new lines, not spaces).

Marisha
  • 816
  • 9
  • 14
  • can you elaborate more on this? what is a shell expansion? how to use `-1` to separete by lines? – Antonio Feb 23 '20 at 02:50
  • @Antonio Araujo, shell expansion is the shell (e.g. bash) will replace * with list of files - can read more on bash man page. -1 is ls command option, echo is other command, it does not have same options. – Marisha Feb 23 '20 at 18:15
5

fd

Using fd (alternative to find), use the following syntax:

fd . foo -a

Where . is the search pattern and foo is the root directory.

E.g. to list all files in etc recursively, run: fd . /etc -a.

-a, --absolute-path Show absolute instead of relative paths

kenorb
  • 155,785
  • 88
  • 678
  • 743
5

If you need list of all files in current as well as sub-directories

find $PWD -type f

If you need list of all files only in current directory

find $PWD -maxdepth 1 -type f
Thyag
  • 1,217
  • 13
  • 14
2

You might want to try this.

for name in /home/ken/foo/bar/*
do
    echo $name
done

You can get abs path using for loop and echo simply without find.

fangxlmr
  • 21
  • 2
2

find jar file recursely and print absolute path

`ls -R |grep "\.jar$" | xargs readlink -f`                                                                                                                                                                                                                                                               
/opt/tool/dev/maven_repo/com/oracle/ojdbc/ojdbc8-19.3.0.0.jar
/opt/tool/dev/maven_repo/com/oracle/ojdbc/ons-19.3.0.0.jar
/opt/tool/dev/maven_repo/com/oracle/ojdbc/oraclepki-19.3.0.0.jar
/opt/tool/dev/maven_repo/com/oracle/ojdbc/osdt_cert-19.3.0.0.jar
/opt/tool/dev/maven_repo/com/oracle/ojdbc/osdt_core-19.3.0.0.jar
/opt/tool/dev/maven_repo/com/oracle/ojdbc/simplefan-19.3.0.0.jar
/opt/tool/dev/maven_repo/com/oracle/ojdbc/ucp-19.3.0.0.jar

geosmart
  • 518
  • 4
  • 15
2

This works best if you want a dynamic solution that works well in a function

lfp ()
{
  ls -1 $1 | xargs -I{} echo $(realpath $1)/{}
}

Daniel Kobe
  • 9,376
  • 15
  • 62
  • 109
1

Here's an example that prints out a list without an extra period and that also demonstrates how to search for a file match. Hope this helps:

find . -type f -name "extr*" -exec echo `pwd`/{} \; | sed "s|\./||"
Mike Behr
  • 43
  • 4
1

This worked for me. But it didn't list in alphabetical order.

find "$(pwd)" -maxdepth 1

This command lists alphabetically as well as lists hidden files too.

ls -d -1 "$PWD/".*; ls -d -1 "$PWD/"*;
Raveen Kumar
  • 71
  • 1
  • 10
1

stat

Absolute path of a single file:

stat -c %n "$PWD"/foo/bar
kenorb
  • 155,785
  • 88
  • 678
  • 743
1

This will give the canonical path (will resolve symlinks): realpath FILENAME

If you want canonical path to the symlink itself, then: realpath -s FILENAME

JGurtz
  • 1,085
  • 11
  • 17
1

Most if not all of the suggested methods result in paths that cannot be used directly in some other terminal command if the path contains spaces. Ideally the results will have slashes prepended. This works for me on macOS:

find / -iname "*SEARCH TERM spaces are okay*" -print 2>&1  | grep -v denied |grep -v permitted |sed -E 's/\ /\\ /g'
Adam
  • 11
  • 1
1
for p in <either relative of absolute path of the directory>/*; do
    echo $(realpath -s $p)
done
YouJiacheng
  • 449
  • 3
  • 11
0
lspwd() { for i in $@; do ls -d -1 $PWD/$i; done }
rxw
  • 2,249
  • 3
  • 19
  • 14
0

Recursive files can be listed by many ways in Linux. Here I am sharing one liner script to clear all logs of files(only files) from /var/log/ directory and second check recently which logs file has made an entry.

First:

find /var/log/ -type f  #listing file recursively 

Second:

for i in $(find $PWD -type f) ; do cat /dev/null > "$i" ; done #empty files recursively 

Third use:

ls -ltr $(find /var/log/ -type f ) # listing file used in recent

Note: for directory location you can also pass $PWD instead of /var/log.

Yuri
  • 4,254
  • 1
  • 29
  • 46
linux.cnf
  • 519
  • 6
  • 7
0

If you don't have symbolic links, you could try

tree -iFL 1 [DIR]

-i makes tree print filenames in each line, without the tree structure.

-f makes tree print the full path of each file.

-L 1 avoids tree from recursion.

0

Write one small function

lsf() {
ls `pwd`/$1
}

Then you can use like

lsf test.sh 

it gives full path like

/home/testuser/Downloads/test.sh
Renju Ashokan
  • 428
  • 6
  • 18
0

I used the following to list absolute path of files in a directory in a txt file:

find "$PWD" -wholename '*.JPG' >test.txt
Obsidian
  • 3,719
  • 8
  • 17
  • 30
-1
ls -1 | awk  -vpath=$PWD/ '{print path$1}'
Albert
  • 1