ls_name_value - Man Page

for browsing names and corresponding values in sysfs

Synopsis

ls_name_value [--all] [--dir] [--empty] [--help] [--native] [--nosym] [--num=NUM] [--otherfs] [--physical] [--show] --utf8] [--verbose] [--version] [--write] [--] [NAME ...]

Description

This bash shell script is designed to give an overview of the (file)names and their corresponding values in the sysfs pseudo file system found in Linux. For regular files, only printable (7 bit) ASCII is shown for each value, on the same line following the (file)name and a colon. That will be referred to as a "name:value pair" in the following.

If no NAME is given then all regular files in the current directory have their name:value pairs displayed. Hidden regular files (i.e. those starting with ".") are not shown. If a regular file is empty (zero length) then nothing is output for its value except if the --empty option is given in which case "<empty>" is output. By default directory names and symbolic links (symlinks) are not shown. One exception is a symlink to a regular file which is shown like this:
   $ ls_name_value /dev/core
     core ---> /proc/kcore : <cannot access>

In this case /dev/core is a symlink to /proc/kcore (and thus /proc/kcore is called the symlink target). The current user doesn't have permissions to read that file (because it is "raw" memory) so its value (or the first 80 bytes of its value) is replaced by "<cannot access>". Even if root made the same invocation, the value most likely would be replaced by this string "<contains non-ASCII chars>".

If one or more NAMEs are given then their corresponding name:value pairs are displayed. An exception is if only one NAME is given and that is a directory (or a symlink to a directory) then that directory is entered and all regular files in that directory have their name:value pairs displayed.

A simple example follows where "power_role" is a regular file:
   $ ls_name_value /sys/class/typec/port1/power_role
     power_role : [source] sink

The value part of the name:value pair is output when the name is a readable, regular file. Furthermore the value is output if it only contains 7 bit ASCII characters, if not "<contains non-ASCII chars>" is output instead. By default, up to 80 characters are output, that number can be changed with the --num=NUM option. If the name has write permissions set for the accessing user and no read permissions set then the value is replaced by "<write_only>". If the name is a regular file and cannot be read from then the value is replaced by "<cannot access>". If the value cannot be read within 2 seconds, the value output is "<timeout>".

This script is designed to obtain an overview of adjacent name:value pairs in the same or nearby directories. This is done at the expense of accurate renderings of the associated values. Other tools may be used to get better renderings of particular values, for example the od and hd (hexdump) Unix commands if the value contains binary data.

This script may also be suitable for other pseudo file systems, but not if they pause a Unix read(2) waiting for an event to occur. The tracefs pseudo file system has waiting read(2)s and this is an issue since an instance of tracefs is often mounted under sysfs (e.g. /sys/kernel/tracing ). Due to this issue, every time this script tries to enter a directory, it checks if it is still in the original file system instance. If not, it does not enter and outputs a "<different filesystem>" message. Here is an example that shows this when two NAMEs are given on the command line:
   $ ls_name_value -d /dev /sys
     >> enter directory: /dev
         core ---> /proc/kcore : <cannot access>
     >> not entering directory: /sys : <different filesystem>
This occurs because /dev is contained in an instance of the devfs file system while /sys is contained in an instance of sysfs.

The filenames in each directory are read with the ls command. If the --all option is given then "ls -A" is used and that adds hidden files. The order in which filenames appear is the same as the "ls" command which depends on the user's locale. More precisely the "--zero" option is also used to handle filenames containing "strange" characters.

Options

Arguments to long options are mandatory for short options as well. The options are arranged in alphabetical order based on the long option name.

-a,  --all

following Unix practice, by default when filenames in a directory are listed, those starting with '.' are hidden (i.e. not listed). When this option is given, filenames starting with '.' are included. The pseudo filenames '.' and '..' are excluded. For a directory only holding regular files the number and order in which they are shown is the same as that shown by the 'ls -A' command.

-d,  --dir

When give once, if any files in the NAME list are directories, then this script enters each directory and lists its name:value pairs. Those name:value pairs are preceded by four spaces to show 1 level of nesting. If the NAME list is empty, then the contents of the current working directory are used as a name list.
If this option is given twice, then up to two levels directories are entered. The name:value pairs at the second level are preceded by eight spaces.
The is a special case when a single element NAME list is given and that name is a directory (or a symlink to a directory). This script will enter nix that directory and list its name:value pairs without the need for this option.
The action of this option is similar to the -maxdepth <n> option in the Unix find(1) command.

-e,  --empty

in many cases the value associated with a filename is empty. By default, nothing will appear to the right of the colon separating the name and value. When this option is given, if the value is empty, the string '<empty>' is output.
Additionally, if this option is given twice, if a filename is regular, accessible and only contains the '\n' character (a linefeed) then "<LF>" is output. Note that if this option is not given twice then that '\n' control character would be replaced by a space in the output.

-h,  --help

print out the usage message then exit.

-f,  --native

this utility uses the ls command when listing out name:value pairs in a directory. The ls command sorts the filenames in a directory based on the user's locale. Directories have a "native" order (probably based on the (time) order of file/directory creation). That order is the same as what would be seen with the 'ls -f' command (hence the choice of short option). When this option is given the order of the files are shown within a directory is the same as 'ls -f'.
When multiple file names are given on the command line, that is the order that they will be processed by this utility, irrespective of this option.

-N,  --nosym

in sysfs most symlinks (symbolic links) point to other directories rather than regular files. Sometimes following symlinks and expanding the directory adds too much noise so this option prunes out symlinks to directories. So if used with the --dir option, then normal directories will be entered but not symlinks to directories. Without this option when the --dir option is used, both normal directories and symlinks to directories would be entered.

-n,  --num=NUM

NUM is the maximum number of bytes in the values shown. NUM is required to be greater than zero. The default for NUM is 80 bytes.
This option does not apply to the destination path shown for symlinks or the directory name when descending into that directory.
If attempting to read NUM bytes takes longer that 2 seconds then the string "<timeout>" replaces the value.

-o,  --otherfs

as explained in the Description section above, sometimes entering into directories in other file systems can cause issues. So the default action is to prune any branch (directory) that is not in the same file system as the first file (which may be a directory) processed. Giving this option skips the file system check.

-p,  --physical

when this option is given, in the line following "enter directory: ..." the physical path of the entered directory is shown. It takes the full line with no indentation and is surrounded by square brackets (because it is a directory). The output shown is the equivalent of the 'pwd --physical' ( or 'pwd -P'). That is an absolute path (i.e. starts at the root '/') and contains no symlinks. Every distinct file (directory, etc) has a unique physical path as, in the absence of symlinks, file systems are single parent hierarchies.

-s,  --show

usually only regular files are shown in name:value pair format. The main exception is a directory which this utility will "descend" (or enter) into (typically due to the --dir option being given). See the Examples section below.
Directories that are not visited are not shown by default. Also other file types, sometimes called "specials" are not shown. Those specials include char and block devices, named pipes and sockets. Symlinks have a name within a directory plus they have a target which is a directory path that may be absolute (i.e. starting the directory root: '/') or relative (i.e. relative to the location of the directory holding the symlink's name). The last element of the target path (basename) may "point" to a regular file, a directory, another symlink, a special file or be "dangling" (i.e. not pointing to anything valid). Symlinks are also said to be dangling if any element of their target path is invalid. In the extreme, two symlinks can target each other forming an infinite loop if any software attempts to find the "bottom" of the hierarchy.
For other special file types the value is the file type between angle brackets: <block device>, <char device>, <named pipe>, <socket>. There are some other file "types" such as <missing>, <write only> and <cannot access> for a permissions problem.

-u,  --utf8

when examining the contents of a file (i.e. the "value" in name:value pairs) once the top bit of any byte is set, then the default value output will be either "<contains non-ASCII chars>" or "<might be UTF-8>". If a non UTF-8 byte is detected then the whole "value" is considered non-ASCII. If a truncated UTF-8 code point is detected (truncated due to --num=NUM) then if that is the only (partial) UTF-8 encode sequence then the "value" is consider non-ASCII, otherwise it is consider UTF-8. When this option is given instead of outputting "<might be UTF-8>" then the UTF-8 string itself is output. For the actual UTF-8 encode sequences to be rendered the locale must be set appropriately. For example on the author's laptop 'env | grep LANG' yields "LANG=en_CA.UTF-8" and UTF-8 encoded sequences are rendered properly.

-v,  --verbose

increase level or verbosity.

-V,  --version

prints out the version string then exits.

-w,  --write

the separator between the <name> and <value> is normally ":". If this option is given and the filename <name> has both read and write permissions for the current user then the separator is changed to "+".

--

In common with many Unix commands, the '--' option flags that any further arguments on the command line are not options. This becomes important if any filenames start with '-'. Doing that is not a good idea, but sometimes fingers slip or programs that generate file names can be sloppy (or mischievious). With this utility if any given files or directories (to a maximum depth of 2) could start with a '-' the adding the '--' (end of) option(s) will be helpful. This is also the case even when there are no [NAME ...] arguments on the command line.

Examples

Here is an example of the same location with different combinations of the --show option and the --dir option:

   $ ls_name_value /sys/class/usb_power_delivery/

   $ ls_name_value /sys/class/usb_power_delivery/ -s
     pd0 ---> [../../devices/platform/USBC000:00/usb_power_delivery/pd0]
     pd1 ---> [../../devices/platform/USBC000:00/usb_power_delivery/pd1]

   $ ls_name_value /sys/class/usb_power_delivery/ -d
     >> enter directory: pd0 ---> [ ../../devices/platform/USBC000:00/usb_power_delivery/pd0 ]
         revision : 2.0
         uevent : DEVTYPE=usb_power_delivery
     >> enter directory: pd1 ---> [ ../../devices/platform/USBC000:00/usb_power_delivery/pd1 ]
         revision : 2.0
         uevent : DEVTYPE=usb_power_delivery

   $ ls_name_value /sys/class/usb_power_delivery/ -s -d
     >> enter directory: pd0 ---> [ ../../devices/platform/USBC000:00/usb_power_delivery/pd0 ]
         device ---> [../../../USBC000:00]
         [power]
         revision : 2.0
         [sink-capabilities]
         subsystem ---> [../../../../../class/usb_power_delivery]
         uevent : DEVTYPE=usb_power_delivery
     >> enter directory: pd1 ---> [ ../../devices/platform/USBC000:00/usb_power_delivery/pd1 ]
         device ---> [../../../USBC000:00]
         [power]
         revision : 2.0
         ....

The location given (/sys/class/usb_power_delivery/) is a directory that contains two symlinks (pd0 and pd1) and no regular files. Hence the first invocation finds no regular files so it lists nothing. The second invocation add the --show option which lists the two symlinks whose targets are both directories. Directory names are surrounded by brackets ( e.g. "[power]" shown in the last invocation). The third invocation is with the --dir option which enters (descends into) one level of directories. The names of the directories entered (actually symlinks to directories) are shown, together with the regular files found in those directories (i.e. "revision" and "uevent") together with their contents (after the ":").  The last invocation uses both the --show and the --dir options, so the pd0 and pd1 (symlinks to) directories are entered and their contents are listed. The regular files shown together with directories (surround by "[" and "]") and the symlink "subsystem" whose target is a directory (again indicated by the surrounding "[" and "]"). Symlinks are shown with their name followed by "--->" and then the target path which is often but not always a directory.

The next example shows the effect of the --physical option. It expands on the third example if the above section:

   $ ls_name_value /sys/class/usb_power_delivery/ -d -p
     >> enter directory: pd0 ---> [ ../../devices/platform/USBC000:00/usb_power_delivery/pd0 ]
     [ /sys/devices/platform/USBC000:00/usb_power_delivery/pd0 ]
         revision : 2.0
         uevent : DEVTYPE=usb_power_delivery
     >> enter directory: pd1 ---> [ ../../devices/platform/USBC000:00/usb_power_delivery/pd1 ]
     [ /sys/devices/platform/USBC000:00/usb_power_delivery/pd1 ]
         revision : 2.0
         uevent : DEVTYPE=usb_power_delivery

A new line is added after the "enter directory:" line. It is the absolute, physical path of the directory just entered into. It has no indentation and is surrounded by "[" and "]" because it is a directory. A physical path contains no symlinks (in any of its component parts).

There is no command line option to exclude directories which would be useful when using the --dir option. A case where this might be helpful is in procfs (e.g. /proc ) as descending into each running process (thread) may create a lot of noise and perhaps a loop as the ls_name_value script itself is creating (and removing) lots of processes (threads) as it scans. Processes in that directory will match a grep regex like "^[0-9]" which means starting with a digit.
   $ cd /proc
   $ ls_name_value -n 32 -d  $( ls -A | grep -v "^[0-9]" )
The '-v' option on grep inverts a selection (e.g. "give me the lines that do not match ..."). The above invocation shows up to 32 bytes of the contents of regular files in /proc and descends into all directories that do not start with a digit (i.e. information about every running process). For the directories that it does descend into, it will show up to 32 bytes of the contents of regular files it finds, indented by four spaces. There still is a directory called "thread-self" that is a symlink to the process directory that is scanned. The --nosym option would prune the "thread-self" along with any other symlinks (and there are several). In some senses symlinks are evil.

To list the contents of all files called 'connect_type' in sysfs, the following could be done:
   $ find /sys -name connect_type -print0 | xargs -0 ls_name_value
The output will be one line per match. The 'cat' utility could be used but ls_name_value guards against long files and files containing binary that could trash the console output. If there are a lot of matching files then the maximum size of a command line may become an issue. If so:
  $ find /sys -name connect_type -exec ls_name_value {} \;
should do the trick. If the filename contained spaces then the second version would have problems. It doesn't in the case of 'connect_type' but sysfs does contain a few filenames with spaces: "/sys/bus/pnp/drivers/i8042 aux" .

Notes

This utility's functionality overlaps somewhat with the systool utility. systool knows the high level structure of sysfs and offers a better overview. However if information is deeply nested (e.g. /sys/class/typec/ for USB PD) then this utility gives better "drilling down" facilities. For example the USB PD source capabilities of an AC adapter powering a laptop may be found at /sys/class/typec/port1-partner/usb_power_delivery/source-capabilities/* which can be better viewed with this utility.

In software, hierarchies such as computer file systems are often view as inverted trees with the root (called "/" in Unix) at the top and files as leaves at or toward the bottom of the inverted tree. Each leaf has one and only one parent, and the parent is a (named) directory. This rather clean (but somewhat restrictive) model is ruined by symbolic links.

When using this utility on sysfs, the dynamic nature of sysfs (often reflecting ongoing changes in the system) can upset things. For example between detecting the presence of a directory within sysfs and this utility scanning the contents of that directory, that directory might be deleted (e.g. by the kernel because the hardware it represents has just been hot unplugged). To get a more stable snapshot (or close to snapshot) the clone_pseudo_fs utility might be used to clone /sys into /tmp/sys before this utility is used to data-mine within /tmp/sys .

This utility is a bash script but it has a C program helper called ls_name_value_rd for processing the contents of a file. That was initially done in the bash script but handling all the corner cases was too complex and too slow. The ultimate "killer" was the timeout command that takes around 100 milliseconds even when the data (e.g. reading a short sysfs regular file) is available immediately.

Authors

Written by D. Gilbert

See Also

lsscsi(this package), od(GNU coreutils), hd(util-linux), getopt(1) systool(sysfsutils), udevadm(systemd), clone_pseudo_fs(clone_pseudo_fs)

Info

2026-09-13 lsscsi-0.33