1

I want to list all the files in a folder and their respective absolute paths line by line as below,

filename1  /home/.../file1  
filename2 /home/.../file2  
filename3 /home/.../file3  

I tried with find $(pwd) -type f, but it only gives the paths.

4
  • 3
    Your example seems to have conflicting filenames. e.g. filename1 and file1. What am I miss-understanding? Apr 13, 2019 at 9:38
  • what kind of absolute path are those? why /home/../file1 and not /file1 or /home/some_user/../../file1? also, are filename1, filename2, etc symlinks?
    – mosvy
    Apr 13, 2019 at 9:57
  • (1) The way to show that you’re leaving out information is with three dots: ....  Two dots (..) means something else in a pathname, so, please, don’t use .. if you mean ....  But it would be better not to omit information at all, but just show what you mean, e.g., /home/user347009/file1. (2) And either make the filenames consistent or explain why they aren’t.  (For example, do you mean filename1   /home/user347009/dir1?) Apr 13, 2019 at 16:07
  • yes.I just used an example and the dots were put to say that there is a middle part.what i want is as you mentioned, filename1   /home/user347009/dir1/filename1
    – HirSK
    Apr 14, 2019 at 10:32

8 Answers 8

4

Using GNU find:

find "$PWD" -type f -printf '%f %h/%f\n'
  • %f File's name with any leading directories removed (only the last element).
  • %h Leading directories of file's name (all but the last element). If the file name contains no slashes (since it is in the current directory) the %h specifier expands to `.'.
2
  • 2
    Or %p instead of %h/%f Apr 13, 2019 at 19:05
  • @StéphaneChazelas Exactly! I missed it when I was looking at the man page.
    – Freddy
    Apr 13, 2019 at 19:11
3

With standard find:

find "$PWD" -type f -exec sh -c '
    for pathname do
        printf "%s\t%s\n" "${pathname##*/}" "$pathname"
    done' sh {} +

This would print a tab-delimited list of all files in or below the current directory. The first column would contain the filename of the file, and the second column would contain the pathname of the file relative to the absolute path of the current directory (the $PWD in the search path).

This is done by feeding batches of found pathnames to a short in-line script which simply outputs the names in the preferred format. The parameter substitution ${pathname##*/} expands to the value of $pathname with everything up to the last / removed.

Note that filenames containing newlines would be presented on several lines, and that it would be difficult to distinguish filenames containing tab-characters properly. Assuming that the result would be for viewing rather than parsing, that might be okay.

1

Hi and thanks for mentioning fselect!

The problem with odd filenames is not new obviously. We can't even be sure that the filename and its path will be on the same line in case they contain \n within. To address those issues fselect supports the INTO option.

The simplest variant is to use INTO LIST for further parsing with xargs. One can be interested in INTO JSON for more elaborate processing.

2
  • 1
    Note that standard JSON can't encode arbitrary file paths as JSON strings are UTF-8 and file paths are arbitrary sequences of non-0 bytes. May 6 at 10:25
  • fselect seems to convert all bytes that can't be decoded into a UTF-8 character to UTF-8 encoded U+FFFD (�), even in locales that don't use UTF-8 as the encoding, even with INTO LIST. May 6 at 10:38
1

I would like to mention fselect which is written in Rust and uses a SQL(ish) syntax which I can remember a bit more easily:

fselect name, abspath from .

For illustrating the relevant issue with spaces and new lines as in filename posted by @ilkkachu in comments, here's an example with 2 files: a b c and x\ny\nz:

$ fselect name, abspath from . order by name
a b  c  /path/to/a b  c
x
y
z       /path/to/x
y
z

In fselect there is the json output which might help:

$ fselect name, abspath from . order by name into json
[{"Name":"a b  c","AbsPath":"/path/to/a b  c"},{"AbsPath":"/path/to/x\ny\nz","Name":"x\ny\nz"}]

This find command should work also:

find . -type f -exec basename {} \; -exec realpath {} \; | xargs -n 2

xargs -n2 helps putting the output on the same line (please see comments)

6
  • 1
    xargs (without further arguments) will also blow up in face of even filenames with whitespace. You probably want to at least use xargs -d '\n' to only use the newline as delimiter, if your xargs supports it. (That'd still have issues if the filenames contain newlines, or if a file was called -e. Without other arguments, xargs runs echo and it might take the -e as an option.) Using find -exec sh -c ... would be safer
    – ilkkachu
    May 4 at 18:03
  • Indeed I've been blown up in face! Thanks and sorry for not thouroughly testing. I thought I could overcome the issue with find ... -print0 | xargs -0 ... but was unsuccessful. Why? xargs -L2 (xargs from GNU findutils 4.7.0) gave better results with space or new line delimited filename, but not esoteric name like "-e". @ilkkachu Would you recommand xargs -L2 for updating or removing my find/xargs answer? fselect gave better results with space and newline in filenames, even though new line are displayed in more than 1 line and not escaped, which seems strange.
    – jgran
    May 5 at 8:55
  • 1
    if you use find -exec basename etc., the output comes from basename itself, so -print0 from find doesn't affect that. (And with find -exec basename {} \; -print0, you'd get one output from basename, another from -print0.) With basename+realpath, you get the output as lines, and xargs -d '\n' matches that ok. I would probably do something like the find -exec sh -c ... in Kusalananda's in a case that requires running two different commands per filename. (In this particular case, find -printf would be easier with GNU find.)
    – ilkkachu
    May 5 at 10:05
  • I don't have fselect, I didn't try to see what happens with it, so I can't say about any oddnesss it has.
    – ilkkachu
    May 5 at 10:05
  • It's not limited to space and newline. It's also tab and possible other whitespace characters and single quotes, double quotes and backslashes. underscore is also a problem with some xargs implementations as well as long file paths or bytes not forming part of valid characters in the user's locale. May 6 at 13:41
0

With zsh:

for f (**/*(DN)) print -r -- $f $f:P

$f:P does the equivalent of realpath() so expands to the canonical absolute path of the file (expanding all symlinks in the path components to their target, recursively).

-1

The following bash oneliner will produce the output you want

for f in $(find $(pwd) -type f); do echo "$(basename $f) $(realpath $(dirname $f))"; done

Explanation:
for _ in _ ; do _ ; done iterates over what your command found
basename strips all but the last part from a path (aka. the filename)
dirname does the opposite
realpath returns the actual path (so you don't get . for file in cwd)

If you use this frequently, I suggest aliasing the oneliner to a shorter command.

-1

Use this cmd:

find $PWD -type f -printf '%f %h/%f/n'

or

Looking for some files then go with this:

find $PWD -type f -iname "filenames" -printf '%f %h/%f/n'
2
  • Thank you very much.I used your first code. I think there should be a simple modification to as '%f %h/%f\n'.
    – HirSK
    Apr 14, 2019 at 10:38
  • how to display the filename without its extension?
    – HirSK
    Apr 14, 2019 at 11:58
-2

You can use the following cmd for searching the files with their absolute paths. E.g. I am trying to search .sh files using cmd as follows:

find . -type f -iname "*.sh"
1
  • 1
    This would not output two column with the filename in the first and the pathname in the second. It's also unclear why you restrict the search to files with a particular filename suffix when this was not part of the question.
    – Kusalananda
    Apr 13, 2019 at 9:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.