0

There is a directory that contains only symbolic link files.

I'd like to pipe over the ls command from this directory and give it as a factor for the readlink command to print out the original file

I tried the command below, but I couldn't find the answer

$ ls opt/integrity/ | xargs readlink

Does anyone know the appropriate command to output the original file via ls and readlink commands for all files that exist in the directory

muru
  • 72,889

2 Answers2

1

There is absolutely no need to use ls to list the files for readlink (it's intended to provide a convenient listing of files for people not for machines). Instead you can have the shell expand * to match all files in the directory

readlink opt/integrity/*

Your original command would have probably worked, provided that the path opt/integrity existed and none of the source filenames contained spaces (or other "special" characters). But a wildcard handles this already so is a safer solution.

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
1

If you mean that you want to list symlinks along with the target paths they point to, with zsh:

$ zmodload zsh/stat
$ stat -n +link /dev/*(@)
/dev/cdrom sr0
/dev/core /proc/kcore
/dev/fd /proc/self/fd
/dev/initctl /run/initctl
/dev/log /run/systemd/journal/dev-log
/dev/rtc rtc0
/dev/stderr /proc/self/fd/2
/dev/stdin /proc/self/fd/0
/dev/stdout /proc/self/fd/1

With the ast-open implementation of ls, you can also do:

$ ls -d --format='%(name)s %(linkpath)s' /dev/*(@)
/dev/cdrom sr0
/dev/core /proc/kcore
/dev/fd
/dev/initctl /run/initctl
/dev/log /run/systemd/journal/dev-log
/dev/rtc rtc0
/dev/stderr /proc/self/fd/2
/dev/stdin /proc/self/fd/0
/dev/stdout /proc/self/fd/1

With GNU find:

$ find /dev/ -maxdepth 1 -type l -printf '%p %l\n'
/dev/cdrom sr0
/dev/rtc rtc0
/dev/log /run/systemd/journal/dev-log
/dev/initctl /run/initctl
/dev/core /proc/kcore
/dev/stderr /proc/self/fd/2
/dev/stdout /proc/self/fd/1
/dev/stdin /proc/self/fd/0
/dev/fd /proc/self/fd

(unsorted and includes hidden files if any).

With GNU stat:

$ command stat -c %N /dev/*(@)
'/dev/cdrom' -> 'sr0'
'/dev/core' -> '/proc/kcore'
'/dev/fd' -> '/proc/self/fd'
'/dev/initctl' -> '/run/initctl'
'/dev/log' -> '/run/systemd/journal/dev-log'
'/dev/rtc' -> 'rtc0'
'/dev/stderr' -> '/proc/self/fd/2'
'/dev/stdin' -> '/proc/self/fd/0'
'/dev/stdout' -> '/proc/self/fd/1'

path/to/*(@) expands to the non-hidden files of type symlink in the path/to directory, using the @ glob qualifier. That feature is zsh-specific. In other shells you generally need to resort to find to select files based on their type.

For instance, in bash 4.4+, and on GNU systems, the equivalent of expanding /dev/*(@) would be something like:

readarray -td '' files < <(
  LC_ALL=C find /dev/ -mindepth 1 -maxdepth 1 ! -name '.*' -type l -print0 |
    sort -z
)
if (( ${#files[@]} )); then
  stat -c %N -- "${files[@]}"
else
  echo>&2 No match.
fi