46

Similar to a previous question about finding network device names, I would like to get a (reliable) list of device names but just for Wi-Fi devices. So that it looks like the following depending on your naming structure:

wlan0
wlan1

or

wlp5s0
wlp5s1

9 Answers 9

45

With nmcli you could list all devices and their type e.g.

nmcli --get-values GENERAL.DEVICE,GENERAL.TYPE device show
eno1
ethernet

wlp1s0
wifi

wlp1s1
wifi

p2p-dev-wlp1s0
wifi-p2p

lo
loopback

Per the manual, when using -g, --get-values, the "output is terse. This mode is designed and suitable for computer (script) processing". So you can pipe that output to other tools and get the wifi devices names e.g.

nmcli ... | sed '/^wifi/!{h;d;};x'

or

nmcli ... | awk '/^wifi/{print dev; next};{dev=$0};'

On linux you also have iw (show/manipulate wireless devices and their configuration) and when used with the dev command:

Commands:
    dev
        List all network interfaces for wireless hardware.

that is

iw dev

you'll get something like:

phy#0
    Interface wlan0
        ifindex 3
        wdev 0x1
        addr 00:12:32:e4:18:24
        type managed
phy#1
    Interface wlan1
        ifindex 4
        wdev 0x2
        addr 00:12:22:c6:b2:0a
        type managed

To extract only interfaces names you could process the output e.g.

iw dev | awk '$1=="Interface"{print $2}'

just keep in mind the help page clearly states:

Do NOT screenscrape this tool, we don't consider its output stable.
5
  • 1
    I like this answer, it solves the problem, but the bit about not scraping concerns me and makes me think there may be a better way. I'd like to leave this open for now. Commented Jun 2, 2016 at 16:51
  • The 'Do NOT screenscrape' comment only seems to appear when help is shown, due to invalid input or an explicit help command, but not in the output of valid results. Commented Aug 19, 2020 at 3:31
  • Just a reminder that you may need to run this as root i.e. sudo iw dev, because running it as a non-privileged user may return no results. Commented Dec 3, 2020 at 8:02
  • What to "screenscrape" then?
    – Artfaith
    Commented Jun 14, 2021 at 9:59
  • 1
    MattCopperwaite and @Artfaith - see updated answer for a safe-to-parse alternative... Commented Dec 16, 2022 at 14:08
19

On Ubuntu at least, there is the /proc/net/wireless file that contains details about the Wi-Fi interfaces. Which outputs for me:

$ cat /proc/net/wireless
Inter-| sta-|   Quality        |   Discarded packets               | Missed | WE
 face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon | 22
wlp5s0: 0000   36.  -74.  -256        0      0      0     16  33004        0

It's a little messy but the device name is in there.

To get just the interface name:

cat /proc/net/wireless | perl -ne '/(\w+):/ && print $1'

The perl code prints the string of word characters preceding the colon.

2
  • 1
    This did not work for me –probably because I have my wireless card disabled (but detectable).
    – imbuedHope
    Commented Jan 17, 2018 at 20:51
  • 5
    This only shows connected networks.
    – Janos
    Commented Nov 1, 2020 at 13:20
14

Universal way (non root) tested on Android 4, Android 7.1 and Android 9 and ArchLinux.

ls /sys/class/ieee80211/*/device/net/
2
  • 3
    Great solution.Your solution also works in SailfishOS Linux and some Ubuntu.
    – SebMa
    Commented Nov 12, 2020 at 15:52
  • Great answer. To dump only relevant info, ls /sys/class/ieee80211/*/device/net/* -d | sed -E 's|^.*(phy[^/]+)/.*/|\1 |'
    – Codebling
    Commented May 7, 2023 at 18:29
10

If you have sysfs mounted at /sys then the following commands work:

$ find /sys/class/net -follow -maxdepth 2 -name wireless | cut -d / -f 5
wlan0
$ find /sys/class/net -follow -maxdepth 2 -name phy80211 | cut -d / -f 5
wlan0

Or, without find:

for dev in `ls /sys/class/net`; do
    [ -d "/sys/class/net/$dev/wireless" ] && echo "$dev"
done

The first finds all devices in /sys/class/net with a wireless directory (which may be more than just WiFi devices) and the second finds devices that are 802.11 compatible

Tested on kernel 4.4

3
  • Even though sysfs probably has sane file names, parsing the output of ls is bad practice and a common pit fall in bash. Commented Jan 27, 2021 at 23:51
  • Good point @StephanHenningsen — this is why I prefer the first solution which uses find
    – Josh
    Commented Jan 27, 2021 at 23:58
  • I like the find solution too; it only finds files that actually exist which solves the awkward * that other solutions here get. I found that I needed a slightly different set of parameters to reduce the amount of noise cause by file system loops. The following works nicely for me, but does spawn an extra subshell for cut and relies on assumptions about indexes: find -H /sys/class/net/* -name wireless | cut -d / -f 5 Furthermore I needed an additional | head -n1 for my particular use-case. Commented Jan 28, 2021 at 0:15
8

Building on Josh's answer, I'll use a shell glob to identify the /sys/class/net directories with a wireless directory inside, and cut to grab the device name:

# find the directories
$ printf '%s\n' /sys/class/net/*/wireless # substitute with phy80211 if desired
/sys/class/net/wlp4s0/wireless
# filter out the "device" part
$ printf '%s\n' /sys/class/net/*/wireless | cut -d/ -f5
wlp4s0
5
  • Note that this will still print * if no wireless device exists, instead of an empty result. Instead, try this with only POSIX shell built-ins: printf '%s\n' /sys/class/net/*/wireless | while IFS='/' read -r -a p;do [ -e "/sys/class/net/${p[4]}" ] && echo "${p[4]}";done.
    – Yeti
    Commented Sep 30, 2020 at 5:18
  • 1
    @Yeti posix-sh doesn’t have arrays though? As for printing the glob versus an empty result, I think (at least for some shells) that depends on nullglob. Commented Sep 30, 2020 at 12:01
  • Why not just filter the unwanted * out: printf '%s\n' /sys/class/net/*/wirelessREMOVETHIS | cut -d / -f 5 | grep -v '*' Commented Jan 27, 2021 at 22:08
  • @StephanHenningsen good use of cut instead of awk, edited. I'm not convinced on the * part though; I really think it depends on what you're doing, what the shell options are, and whether or not your device might have an asterisk in it (shudders) Commented Jan 27, 2021 at 22:10
  • It's just a little star; what could go wrong? Commented Jan 27, 2021 at 22:14
2

Here's a simple and very effective loop that answers the question:

for dev in /sys/class/net/*; do
    [ -e "$dev"/wireless ] && echo ${dev##*/}
done

This one picks the first wireless interface and stores it in $iwdev, which was what I needed:

for dev in /sys/class/net/*; do
    if [ -e "$dev"/wireless ]; then
        iwdev=${dev##*/};
        break;
    fi
done

It's a rewrite of Josh's answer which I found nice and simple. The above approach handles spaces and other oddities in file names. It also doesn't make too many assumptions about file paths being sane and relies on a minimum of slashes and indexing. Finally it uses built-in parameter expansion for extracting the base device name instead of spawning a subshell for cut or awk.

1

Use find command tool

This finds the actual file that contains the name, it should work in most cases and it's really a short command:

# For WiFi
find /sys/class/net/ -name "wlp*" -exec basename \{} \; 
# For Ethernet
find /sys/class/net/ -name "enp*" -exec basename \{} \;
0

Here's the little bash function I wrote to cover more exceptions :

lswifiInterfaces () {
    set -o pipefail # I use this to preserve the return code of the first command in the pipe
    if \ls /sys/class/ieee80211/*/device/net 2> /dev/null; then
        :
    elif \ls -d /sys/class/net/*/wireless 2> /dev/null | awk -F/ '{print$5}'; then
        :
    fi
    set +o pipefail
}
0

A lot of good ideas here, I've been using this.

nmcli device | grep wifi\ | awk '{print $1}'

You must log in to answer this question.

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