3

This will probably seem to be a simple question for advanced users, but I have tried with no success.

I want to get a file list in the terminal using the dir command, having the following format: only one file per line, full path included, but no other info, for example:

/home/user/beginner/file1.txt
/media/beginner/movies/video1.mp4

Now I have observed that I'll get this output automatcally without using switches on external drive folders and directing the output into a file. But on the harddrive it will default to the "names-only in columns" style.

How can I force dir to instead use the output format that I want?

1

3 Answers 3

5

This will do exactly what dir does, but it will print full paths instead of relative paths, including directories, files, symlinks and excluding hidden entries:

find . -maxdepth 1 ! -name '.*' -exec realpath -s {} +
  • find . -maxdepth 1 ! -name '.*' -exec [...] {} +: will list every directory / file / symlink in the current working directory, excluding hidden entries, recursively, limiting the recursion's depth to 1 level (i.e. to the current working directory), passing each entry in the output as an argument to [...];
  • realpath -s: will print the full path of an entry, without resolving symlinks' paths

Since this will print entries based on find's output, I'd print the output of realpath NUL-separating each entry, and I'd sort the output using LC_COLLATE=C sort -z, passing sort's output to xargs -0 printf "%s\n" (to deal with the edge case of filenames containing newlines), and since by now the command has become pretty verbose, I'd also put it in an alias for convenience:

alias my_dir="find . -maxdepth 1 ! -name '.*' -exec realpath -zs {} + | LC_COLLATE=C sort -z | xargs -0 printf '%s\n'"
% tree -a
.
├── dir
│   ├── file1
│   ├── file2
│   └── file3
├── file
├── file_with_\012newline
├── .hidden_file
└── symlink -> /bin

3 directories, 6 files
% alias my_dir="find . -maxdepth 1 ! -name '.*' -exec realpath -zs {} + | LC_COLLATE=C sort -z | xargs -0 printf '%s\n'"
% my_dir
/home/user/playground/dir
/home/user/playground/file
/home/user/playground/file_with_
newline
/home/user/playground/symlink
8
  • I have chosen this answer because it fits my personal needs the best (will also list folders, will not double the path if already present).
    – Shakesbeer
    Commented May 18 at 6:37
  • @Shakesbeer I was still in the process of editing the answer when you accepted it, so if you didn't see it check out the last edit, which makes the thing deal correctly with filenames including newlines
    – kos
    Commented May 18 at 6:41
  • 1
    Note that answers based on find will include hidden files by default (equivalent of dir -A1) - you can add ! -name '.*' to exclude them. Or you could avoid find altogether and use a simple shell glob (which also exclude hidden files by default i.e. without the dotglob option) ex. printf '%s\0' * | xargs -r0 realpath -s or even simpler just realpath -s -- * Commented May 18 at 12:43
  • @steeldriver Wow. realpath -s -- * Now that is amazing.
    – JayCravens
    Commented May 18 at 12:54
  • @JayCravens be aware that it's only really suitable for interactive use - for very large numbers of files the expansion of * may exceed the maximum command line length ARG_MAX. The printf/xargs version doesn't have the same limitation and is better suited for scripting. Commented May 18 at 13:33
4

It's a bit messy, but I got it in one line:

readarray <<< $(dir -1) dir_list; for line in "${dir_list[@]}"; do printf "%s\n" "$line"; done | xargs -I {} echo "$PWD/{}"

It separates each dir -1 into individual "line"s, then iterates the array, appending the echo of $PWD to each xargs line.

4
  • Maybe I'm missing something, but why not just readarray <<< $(dir -1) dir_list; for line in "${dir_list[@]}"; do printf "%s" "${PWD}/${line}"; done?
    – kos
    Commented May 18 at 3:17
  • This seems like a very roundabout way to write dir -1 | xargs -I {} echo "$PWD/{}" - does reading the lines into an array and printing them back out really add anything? Commented May 18 at 12:36
  • @steeldriver Guilty. It's what I do is overthink it, every time. I'm usually trying to teach through commands. Redundancy can be eye opening and works great for learning environments. Case in point; this answer with these two comments, it's pure gold.
    – JayCravens
    Commented May 18 at 12:43
  • @JayCravens I've done it myself plenty of times - sometimes I cringe when I come across some of my older answers lol Commented May 18 at 12:48
4

You can readlink command for that. First run find command to get files in the current directory. Then pipe the list to readlink. For example:

$ find . -maxdepth 1 -type f -print0| xargs -0 readlink -f

Which will list in a single column all the files. If you want directories instead of files then use - type d in find command.

2
  • 1
    Notably, this will list only files, unlike dir (I'm unclear on whether this is what OP actually wants)
    – kos
    Commented May 18 at 3:30
  • 2
    Filenames with spaces will not be handled correctly.
    – ubfan1
    Commented May 18 at 4:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .