165

In a Linux environment, I need to detect the physical connected or disconnected state of an RJ45 connector to its socket. Preferably using BASH scripting only.

The following solutions which have been proposed on other sites do NOT work for this purpose:

  1. Using 'ifconfig' - since a network cable may be connected but the network not properly configured or not currently up.
  2. Ping a host - since the product will be within a LAN using an unknown network configuration and unknown hosts.

Isn't there some state which can be used in the /proc file system (everything else is in there)?

How is the Linux world suppose to have their own version of the Windows bubble that pop up from the icon tray indicating that you've just unplugged the network cable?


Kent Fredric and lothar, both of your answers satisfy my need... thanks a lot! Which one I'll use... I still don't know.

I guess I can't put you both down as the correct answer? And its probably fair for you that I do choose one. Flip a coin I guess? Again, thanks!

Jeach
  • 8,656
  • 7
  • 45
  • 58

16 Answers16

260

You want to look at the nodes in

/sys/class/net/

I experimented with mine:

Wire Plugged in:

eth0/carrier:1
eth0/operstate:unknown

Wire Removed:

eth0/carrier:0
eth0/operstate:down

Wire Plugged in Again:

eth0/carrier:1
eth0/operstate:up

Side Trick: harvesting all properties at once the easy way:

grep "" eth0/* 

This forms a nice list of key:value pairs.

Ricky Robinson
  • 21,798
  • 42
  • 129
  • 185
Kent Fredric
  • 56,416
  • 14
  • 107
  • 150
98

You can use ethtool:

$ sudo ethtool eth0
Settings for eth0:
    Supported ports: [ TP ]
    Supported link modes:   10baseT/Half 10baseT/Full
                            100baseT/Half 100baseT/Full
                            1000baseT/Full
    Supports auto-negotiation: Yes
    Advertised link modes:  10baseT/Half 10baseT/Full
                            100baseT/Half 100baseT/Full
                            1000baseT/Full
    Advertised auto-negotiation: Yes
    Speed: 1000Mb/s
    Duplex: Full
    Port: Twisted Pair
    PHYAD: 0
    Transceiver: internal
    Auto-negotiation: on
    Supports Wake-on: umbg
    Wake-on: g
    Current message level: 0x00000007 (7)
    Link detected: yes

To only get the Link status you can use grep:

$ sudo ethtool eth0 | grep Link
    Link detected: yes
lothar
  • 19,853
  • 5
  • 45
  • 59
  • 1
    ip link | grep BROADCAST |cut -d ':' -f 2 | while read i; do echo $i; ethtool $i | grep Link ; done – Bryan Hunt Mar 24 '12 at 11:52
  • 3
    Note that as Marco says below the interface must be up (even if not configured) to query these values. – Jamie Kitson Aug 25 '12 at 13:28
  • this is awesome! i had a way to check if ethernet is available, if ethernet is enabled, if ethernet is connected but no way to check if the actual cable was connected. `grep Link` does it. Thank you!! – ᴛʜᴇᴘᴀᴛᴇʟ May 18 '16 at 18:43
  • Not working here. Ubuntu 16.04 on HP hardware. unconfigured interfaces are "no link", even when forced to `up` state. – 0xF2 Jun 21 '17 at 12:33
29

Use 'ip monitor' to get REAL TIME link state changes.

Peter Quiring
  • 1,648
  • 1
  • 16
  • 21
  • 3
    In my case, this is the only answer that worked... /sys/class/net/eth0/carrier still shows `1` when my cable is disconnected while `ip monitor` actually shows something – Tim Tisdall Oct 20 '14 at 19:04
  • Some expanding on this method could be thanked, Peter. Something like any example that answer the original question about knowing cable plug state. – Sopalajo de Arrierez Apr 01 '18 at 12:46
18

cat /sys/class/net/ethX is by far the easiest method.

The interface has to be up though, else you will get an invalid argument error.

So first:

ifconfig ethX up

Then:

cat /sys/class/net/ethX
Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
Marco
  • 181
  • 1
  • 2
  • 5
    Try "cat /sys/class/net/eth[n]/operstate" where [n] is the eth device number. – pmont Jun 28 '13 at 16:01
  • This only tells you if eth[n] is up, If it's down it does not tell you if the cable is connected or not. – Brice Jul 11 '15 at 09:04
  • @Brice, indeed, you want to check file `ethX/carrier` which is 1 if the 'carrier' is detected, meaning that a cable is connected and carrying data... – Alexis Wilke May 21 '16 at 04:05
  • This worked for me using Process Runtime Exec commands to check if the cable is connecte in Android. – Arlyn Oct 24 '16 at 16:26
  • Or, after ifconfig ethX up, ifconfig ethX and look for RUNNING. – craig65535 Dec 14 '18 at 00:13
9

On the low level, these events can be caught using rtnetlink sockets, without any polling. Side note: if you use rtnetlink, you have to work together with udev, or your program may get confused when udev renames a new network interface.

The problem with doing network configurations with shell scripts is that shell scripts are terrible for event handling (such as a network cable being plugged in and out). If you need something more powerful, take a look at my NCD programming language, a programming language designed for network configurations.

For example, a simple NCD script that will print "cable in" and "cable out" to stdout (assuming the interface is already up):

process foo {
    # Wait for device to appear and be configured by udev.
    net.backend.waitdevice("eth0");
    # Wait for cable to be plugged in.
    net.backend.waitlink("eth0");
    # Print "cable in" when we reach this point, and "cable out"
    # when we regress.
    println("cable in");   # or pop_bubble("Network cable in.");
    rprintln("cable out"); # or rpop_bubble("Network cable out!");
                           # just joking, there's no pop_bubble() in NCD yet :)
}

(internally, net.backend.waitlink() uses rtnetlink, and net.backend.waitdevice() uses udev)

The idea of NCD is that you use it exclusively to configure the network, so normally, configuration commands would come in between, such as:

process foo {
    # Wait for device to appear and be configured by udev.
    net.backend.waitdevice("eth0");
    # Set device up.
    net.up("eth0");
    # Wait for cable to be plugged in.
    net.backend.waitlink("eth0");
    # Add IP address to device.
    net.ipv4.addr("eth0", "192.168.1.61", "24");
}

The important part to note is that execution is allowed to regress; in the second example, for instance, if the cable is pulled out, the IP address will automatically be removed.

Ambroz Bizjak
  • 7,809
  • 1
  • 38
  • 49
5

There exists two daemons that detect these events:

ifplugd and netplugd

German
  • 113
  • 2
  • 6
  • I use `ifplugstatus` tool from the `ifplugd` daemon. No need for arguments, just type `ifplugstatus` and you will get all the NIC as plugged or unplugged. – Sopalajo de Arrierez May 28 '18 at 09:01
4

I use this command to check a wire is connected:

cd /sys/class/net/
grep "" eth0/operstate

If the result will be up or down. Sometimes it shows unknown, then you need to check

eth0/carrier

It shows 0 or 1

Sarvar Nishonboyev
  • 12,262
  • 10
  • 69
  • 70
3

Some precisions and tricks

  1. I do all this as normal user (not root)

  2. Grab infos from dmesg

    Using dmesg is one of the 1st things to do for inquiring current state of system:

    dmesg | sed '/eth.*Link is/h;${x;p};d'
    

    could answer something like:

    [936536.904154] e1000e: eth0 NIC Link is Down
    

    or

    [936555.596870] e1000e: eth0 NIC Link is Up 100 Mbps Full Duplex, Flow Control: Rx/Tx
    

    depending on state, message could vary depending on hardware and drivers used.

    Nota: this could by written dmesg|grep eth.*Link.is|tail -n1 but I prefer using sed.

    dmesg | sed '/eth.*Link is/h;${x;s/^.*Link is //;p};d'
    Up 100 Mbps Full Duplex, Flow Control: Rx/Tx
    
    dmesg | sed '/eth.*Link is/h;${x;s/^.*Link is //;p};d'
    Down
    
  3. Test around /sys pseudo filesystem

    Reading or writting under /syscould break your system, especially if run as root! You've been warned ;-)

    This is a pooling method, not a real event tracking.

    cd /tmp
    grep -H . /sys/class/net/eth0/* 2>/dev/null >ethstate
    while ! read -t 1;do
        grep -H . /sys/class/net/eth0/* 2>/dev/null |
            diff -u ethstate - |
            tee >(patch -p0) |
            grep ^+
      done
    

    Could render something like (once you've unplugged and plugged back, depending ):

    +++ -   2016-11-18 14:18:29.577094838 +0100
    +/sys/class/net/eth0/carrier:0
    +/sys/class/net/eth0/carrier_changes:9
    +/sys/class/net/eth0/duplex:unknown
    +/sys/class/net/eth0/operstate:down
    +/sys/class/net/eth0/speed:-1
    +++ -   2016-11-18 14:18:48.771581903 +0100
    +/sys/class/net/eth0/carrier:1
    +/sys/class/net/eth0/carrier_changes:10
    +/sys/class/net/eth0/duplex:full
    +/sys/class/net/eth0/operstate:up
    +/sys/class/net/eth0/speed:100
    

    (Hit Enter to exit loop)

    Nota: This require patch to be installed.

  4. In fine, there must already be something about this...

    Depending on Linux Installation, you could add if-up and if-down scripts to be able to react to this kind of events.

    On Debian based (like Ubuntu), you could store your scripts into

    /etc/network/if-down.d
    /etc/network/if-post-down.d
    /etc/network/if-pre-up.d
    /etc/network/if-up.d
    

    see man interfaces for more infos.

F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
  • Thanks for your comments and input on the matter. Although, you do realize that these are 'automated' scripts. In point 2, when you say output '**or**' another output, or when you say "**depending on state, message could vary depending on hardware and drivers used**" ... that's a real big issue. Output must be consistent or production scripts start to break. But it's good information regardless, thank you. – Jeach Oct 06 '17 at 14:28
  • @Jeach Output may vary mean: *You may use another driver than `e1000`* and *evenement could occur at another time than `936555.596870`*, but you allway will see *`NIC Link is`*. – F. Hauri - Give Up GitHub Oct 07 '17 at 07:22
3

Most modern Linux distributions use NetworkManager for this. You could use D-BUS to listen for the events.

If you want a command-line tool to check the status, you can also use mii-tool, given that you have Ethernet in mind.

andri
  • 11,171
  • 2
  • 38
  • 49
2

Somehow if you want to check if the ethernet cable plugged in linux after the commend:" ifconfig eth0 down". I find a solution: use the ethtool tool.

#ethtool -t eth0
The test result is PASS
The test extra info:
Register test  (offline)         0
Eeprom test    (offline)         0
Interrupt test (offline)         0
Loopback test  (offline)         0
Link test   (on/offline)         0

if cable is connected,link test is 0,otherwise is 1.

kyzrong
  • 21
  • 1
1

on arch linux. (im not sure on other distros) you can view the operstate. which shows up if connected or down if not the operstate lives on

/sys/class/net/(interface name here)/operstate
#you can also put watch 
watch -d -n -1 /sys/class/net/(interface name here)/operstate
Skrmnghrd
  • 558
  • 4
  • 10
1

You can use ifconfig.

# ifconfig eth0 up
# ifconfig eth0

If the entry shows RUNNING, the interface is physically connected. This will be shown regardless if the interface is configured.

This is just another way to get the information in /sys/class/net/eth0/operstate.

craig65535
  • 3,439
  • 1
  • 23
  • 49
1
tail -f /var/log/syslog | grep -E 'link (up|down)'

or for me faster gets:

tail -f /var/log/syslog | grep 'link \(up\|down\)'

It will listen to the syslog file.

Result (if disconnect and after 4 seconds connect again):

Jan 31 13:21:09 user kernel: [19343.897157] r8169 0000:06:00.0 enp6s0: link down
Jan 31 13:21:13 user kernel: [19347.143506] r8169 0000:06:00.0 enp6s0: link up
1

This command checks for "state UP" in the 2nd interface of the "ip a" command. I have checked in 2 computers running wifi, the 2nd listed is the cable ethernet. Case you want to check a different interface, just change the "2" in the command below to be the correct index position.

astate=`ip a | grep -E -o -m 1 "2:.*state UP"`  
if [ -n "$astat" ]; then
   echo 'cable is on'
else
   echo 'cable is off'
fi
Sergio Abreu
  • 2,686
  • 25
  • 20
0

On OpenWRT the only way to reliably do this, at least for me, is by running these commands:

# Get switch name
swconfig list

# assuming switch name is "switch0"
swconfig dev switch0 show | grep link:

# Possible output
root@OpenWrt:~# swconfig dev switch0 show | grep link:
        link: port:0 link:up speed:1000baseT full-duplex txflow rxflow
        link: port:1 link:up speed:1000baseT full-duplex txflow rxflow eee100 eee1000 auto
        link: port:2 link:up speed:1000baseT full-duplex txflow rxflow eee100 eee1000 auto
        link: port:3 link:down
        link: port:4 link:up speed:1000baseT full-duplex eee100 eee1000 auto
        link: port:5 link:down
        link: port:6 link:up speed:1000baseT full-duplex txflow rxflow

This will show either "link:down" or "link:up" on every port of your switch.

Jeach
  • 8,656
  • 7
  • 45
  • 58
jvillasante
  • 89
  • 1
  • 5
-1

I was using my OpenWRT enhanced device as a repeater (which adds virtual ethernet and wireless lan capabilities) and found that the /sys/class/net/eth0 carrier and opstate values were unreliable. I played around with /sys/class/net/eth0.1 and /sys/class/net/eth0.2 as well with (at least to my finding) no reliable way to detect that something was physically plugged in and talking on any of the ethernet ports. I figured out a bit crude but seemingly reliable way to detect if anything had been plugged in since the last reboot/poweron state at least (which worked exactly as I needed it to in my case).

ifconfig eth0 | grep -o 'RX packets:[0-9]*' | grep -o '[0-9]*'

You'll get a 0 if nothing has been plugged in and something > 0 if anything has been plugged in (even if it was plugged in and since removed) since the last power on or reboot cycle.

Hope this helps somebody out at least!

JxAxMxIxN
  • 1,711
  • 1
  • 17
  • 20