Executing a command via shell script.

Hello,
I'm new to shell (.sh) scripting, so I lean slowly :) .
I have this command
Code:
 $ dmesg | grep "Ethernet address:" | awk '{ print $1 }' | sed s/://
This command retreive the name if ethernet interface from dmesg kernel journal, and works well when executed from the commande line prompt.
But error is given : not fount when trying to use it in a shell script
Here is the code of script
Code:
#!/bin/sh

#
# Get interface name & replace it.
#
# Get kernel if

Bsd_dmesg="/sbin/dmesg"
Bsd_grep="/usr/bin/grep"
Bsd_sed="/usr/bin/sed"
Bsd_awk="/usr/bin/awk"

# dmesg | grep \"Ethernet address:\" | awk '{ print $1 }' | sed s/://" 
C_ifkern_cmd="${Bsd_dmesg}|${Bsd_grep} \"Ethernet address:\"| ${Bsd_awk} '{ print \$1 }' | ${Bsd_sed} s/://"

  # execute command;
  echo "${C_ifkern_cmd}"
 
  ifnet=$("${C_ifkern_cmd}")
 
  echo "${ifnet}"

exit 0

So please, tel me where is the problem.
The output is
Code:
./ucgetif: /sbin/dmesg|/usr/bin/grep "Ethernet address:"| /usr/bin/awk '{ print $1 }' | /usr/bin/sed s/://: not found
 
You don't need so long chain of commands, here is a simpler way:
Code:
dmesg | sed -n 's/^\(.*\):\ Ethernet\ address.*/\1/p'
 
You need
Code:
ifnet=$(${C_ifkern_cmd}) # without quotes

Also, you should really grep on /var/run/dmesg,boot instead of the live kernel buffer. The latter has the problem that new messages at runtime will over time swap out the messages you want. There is limited space in there.

Why do you feel you need to hardcode the paths?

The grep can be replaced with an AWK statement
Code:
awk '/grepterm/ {print $1}'

In general, as a beginner you should try not to get into the quoting messes resulting from keeping commands in variables. Have you considered using -x?
 
If you just need a list of interfaces; ifconfig -l. No need to grep through system logs.

Code:
     The -l flag may be used to list all available interfaces on the system,
     with no other additional information.  If an address_family is specified,
     only interfaces of that type will be listed.  -l “ether” will list only
     Ethernet adapters, excluding the loopback interface.  Use of this flag is
     mutually exclusive with all other flags and commands, except for -d (only
     list interfaces that are down) and -u (only list interfaces that are up).
ifconfig(8)
 
Don't worry too much about the 'correctness', just have fun and try lots of things. Some learn quickly, some a little slower. But the only way to learn how to do it properly is by actually starting. Everybody's first scripts sucked, my first scripts certainly did ;)
 
Hello.
Here is a working script.
Bash:
#!/bin/sh
#
# Get interface name & replace it.
#
Bsd_dmesg="/sbin/dmesg"
Bsd_grep="/usr/bin/grep"
Bsd_sed="/usr/bin/sed"
Bsd_awk="/usr/bin/awk"
Bsd_cat="/bin/cat"
Bsd_msgd="/var/run/dmesg.boot"

#(works ;) ) eth_addresses=$(cat /var/run/dmesg.boot | sed -n 's/^\(.*\):\ Ethernet\ address.*/\1/p')
#(works ;) ) eth_addresses=$(${Bsd_cat} ${Bsd_msgd} | ${Bsd_sed} -n 's/^\(.*\):\ Ethernet\ address.*/\1/p')
#(works ;) ) eth_addresses=$(${Bsd_dmesg} | ${Bsd_sed} -n 's/^\(.*\):\ Ethernet\ address.*/\1/p')

eth_ifs=$(${Bsd_dmesg} | ${Bsd_sed} -n 's/^\(.*\):\ Ethernet\ address.*/\1/p')
rep_pattern="XXXX"
${Bsd_sed} -i '' -e "s/$rep_pattern/$eth_ifs/g" /etc/rc.conf
exit 0

Thank you.
 
In my case, I do not know it will feel my needs,
I explain.
I have to work an OS image (.img), and after burning it into SDCard or USB Stick and after kernel messages when starting, I must execute this code ( code above) to replace 'XXXX' in the /etc/rc.conf with the interface name.
In my
`/etc/rc.conf `
I added theses entries.
ifconfig_XXXX_name="genet0"
ifconfig_genet0="inet 192.168.1.177/24"
after executing, the XXXX will be replaced by by the interface name without human intervention.

I wonder if there a way to know interfaces names & there characteristics like, Vendor, Type, MAC address without needing to dump dmesg.boot.?
The C code or shell, ... are welcome.

(PS: I must know all these details in boot time after kernel messages ).

Thanks
 
Tip, you can use ifconfig_DEFAULT="....". That will always use the first detected ethernet card. Which is usually fine for most generic servers or embedded devices with only one ethernet adapter.

If you need to use a specific interface (for firewall rules for example), you could do ifconfig_DEFAULT_name="eth0". Then base everything on the eth0 interface name. This little 'trick' would work fine for systems that only have one ethernet connection. No need to figure out if it's ng0, or em0, or igb0, it will automagically pick the first interface.
 
Strange,

# the default interface in my system is "vtnet0" I use FreeBSD 13.2-RPI-aarch64 ( I use QEMU)
ifconfig_DEFAULT_name="genet0"
ifconfig_genet0="inet 192.168.1.177/24"

after rebooting, It stays vtnet0 and the name do not change.
May I missing something ?
 
Oh, you're right. I could have sworn I had this working at some point in time.
 
Hello.
After many tries, I think about writing and /rc.d/* script that must be executed before network stack start, that changes the pattern XXXX from /etc/rc.conf with the detected kernel device name.

The question is : CAN I DO THIS ? and HOW. (Pointing me to a sample exemple is welcome.)
Thank you.
 
if I understand correctly, its main use case is with install scripts using ifconfig_DEFAULT="DHCP". If a static ip is set, lo0 will be set with this ip too.

Here maybe a little bit faster solution using pciconf(8)
Code:
# pciconf -lv | grep -B4 ethernet | head -n 1 | cut -c -4
bge0

The question is : CAN I DO THIS ? and HOW. (Pointing me to a sample exemple is welcome.)
Have a look at rc(8) and rc.subr(8).
There are plenty examples in /etc/rc.d/* and /usr/local/etc/rc.d/* or online.
 
I thought about that earlier how that can be accomplished. Changing the network interface name would be a onetime action. Running the script only once can be done with the firstboot sentinel keyword. For example sysutils/firstboot-pkgs is designed to install packages after first booting a newly installed system.

The relevant part of the script is
Code:
#!/bin/sh

# KEYWORD: firstboot
Also a empty /firstboot file must be present on the new system.

rc.conf(5)
Code:
    firstboot_sentinel
                 (str) This variable specifies the full path to a “first boot”
                 sentinel file.  If a file exists with this path, rc.d scripts
                 with the “firstboot” keyword will be run on startup and the
                 sentinel file will be deleted after the boot process
                 completes.  The sentinel file must be located on a writable
                 file system which is mounted no later than early_late_divider
                 to function properly.  The default is /firstboot.

And second, the script needs to be run before the network configuration:
Code:
# BEFORE: netif
 
W.hâ/t , what I want to do is :
  1. installing the FreeBSD OS ( My version ) on SDCard, USBStick.
  2. After kernel loading & devices driver detection I want that the first ethernet device renamed without human intervention into the system.
  3. So, I created a script above ( script ) to do this.
  4. I've tried to place it into /etc/rc but the network interface starts before it, if I call it from the begin of /etc/rc, the filesystem is read only.
  5. I thought to create and rc.d/ script to do this task before starting a network stack

I do not know if it is a good solution and I do not see other solution
 
  1. So, I created a script above ( script ) to do this.
  2. I've tried to place it into /etc/rc
The rc(8) script needs to have a specific structure, see examples in the manual. Your code can be placed inside the rc.d script, or saved in a location read by the PATH variable and pointed to it.

Non-system rc.d scripts should be placed under directory /usr/local/etc/rc.d.
 
W.hâ/t , what I want to do is :
  1. installing the FreeBSD OS ( My version ) on SDCard, USBStick.
  2. After kernel loading & devices driver detection I want that the first ethernet device renamed without human intervention into the system.
  3. So, I created a script above ( script ) to do this.
  4. I've tried to place it into /etc/rc but the network interface starts before it, if I call it from the begin of /etc/rc, the filesystem is read only.
  5. I thought to create and rc.d/ script to do this task before starting a network stack

I do not know if it is a good solution and I do not see other solution
T-Daemon mentions the keywords you need to use in your rc script. You can use your method or mine or an other, it doesn't matter, as long as you use the correct keywords. Here firstboot doesn't suit you in this case.

Now with what you're trying to accomplish, I would say setting ifconfig_DEFAULT="DHCP" should be enough. Altough I surely won't stop you from messing arrround with stuff.
A quick though, what about wlan interfaces?
 
Feedback.
I created an rc file and put it in :
# operations
$ /usr/local/etc/rc.d/ucgetif
$ chmod +x /usr/local/etc/rc.d/ucgetif

listning of the file /usr/local/etc/rc.d/ucgetif

Bash:
#!/bin/sh

# PROVIDE: ucgetif
# REQUIRE: FILESYSTEMS
# BEFORE: hostname

. /etc/rc.subr

name="ucgetif"
rcvar="ucgetif_enable"

start_cmd="${name}_start"

Bsd_dmesg="/sbin/dmesg"
Bsd_grep="/usr/bin/grep"
Bsd_sed="/usr/bin/sed"
Bsd_awk="/usr/bin/awk"
Bsd_cat="/bin/cat"
Bsd_msgd="/var/run/dmesg.boot"

ucgetif_start() {
      eth_patern="XXXX"
      eth_X=$(${Bsd_cat} /etc/rc.conf | ${Bsd_grep} $eth_patern)
      if [ -n $eth_X ]; then
        eth_ifs=$(${Bsd_dmesg} | ${Bsd_sed} -n 's/^\(.*\):\ Ethernet\ address:.*/\1/p')
        $Bsd_sed -i '' -e "s/$eth_patern/$eth_ifs/g" /etc/rc.conf
      fi 
}

run_rc_command "$1"

Modification done on /etc/rc.conf

After reboot, here is the log :


ELF ldconfig path: /lib /usr/lib /usr/lib/compat /usr/local/lib /usr/local/lib/compat/pkg /usr/local/lib/compat/pkg /usr/local/lib/perl5/5.32/mach/CORE
Setting up harvesting: [UMA],[FS_ATIME],SWI,INTERRUPT,NET_NG,[NET_ETHER],NET_TUN,MOUSE,KEYBOARD,ATTACH,CACHED
Feeding entropy: .
Setting hostname: uc-rpi.uccen.net.
ifconfig: SIOCIFCREATE2 (wlan): Invalid argument
[B]vtnet0: changing name to 'genet0'
genet0[/B]
lo0: link state changed to UP
genet0: link state changed to UP
Starting Network: lo0 genet0.
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
inet 127.0.0.1 netmask 0xff000000
groups: lo
nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
genet0: flags=8863<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=80028<VLAN_MTU,JUMBO_MTU,LINKSTATE>
ether 52:54:00:12:34:56
media: Ethernet autoselect (10Gbase-T <full-duplex>)
status: active
nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
Starting devd.
add host 127.0.0.1: gateway lo0 fib 0: route already in table
add host ::1: gateway lo0 fib 0: route already in table
add net fe80::: gateway ::1
add net ff02::: gateway ::1
add net ::ffff:0.0.0.0: gateway ::1
add net ::0.0.0.0: gateway ::1
Updating motd:.
Clearing /tmp (X related).
Updating /var/run/os-release done.




Conclusion ;
It change effectivelly the interface name ( and modify the XXXX in /etc.rc.conf) , but It do not apply IP address until restart.
Is there any way or I'm messing something.
Thanks

PS: Look at the image
 

Attachments

  • fb.jpg
    fb.jpg
    131 KB · Views: 35
It change effectivelly the interface name ( and modify the XXXX in /etc.rc.conf) , but It do not apply IP address until restart.
Is there any way or I'm messing something.
You are missing the netif script. /etc/rc.d/netif is automaticaly run for network interface setup. ucgetif must run before.

Other, without firstboot sentinel ucgetif will be run every time the system boots up.

Suggestion:
Code:
#!/bin/sh

# PROVIDE: ucgetif
# REQUIRE: FILESYSTEMS
# BEFORE:  netif
# KEYWORD: firstboot

/etc/installerconfig
Code:
...
#!/bin/sh
...
touch /firstboot
...
 
Back
Top