I'd like to get the output of the second command with the 7 character PSI domain (00:01.0) as a variable. How can I write a bash script to do this?

jeff@jeff-probook:/$ lspci | grep VGA
    00:01.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Carrizo (rev c5)
jeff@jeff-probook:/$ lspci -v -s 00:01.0
00:01.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Carrizo (rev c5) (prog-if 00 [VGA controller])
    Subsystem: Hewlett-Packard Company Carrizo
    Flags: bus master, fast devsel, latency 0, IRQ 231
    Memory at c0000000 (64-bit, prefetchable) [size=256M]
    Memory at d0000000 (64-bit, prefetchable) [size=8M]
    I/O ports at 3000 [size=256]
    Memory at d0d00000 (32-bit, non-prefetchable) [size=256K]
    Expansion ROM at d0800000 [disabled] [size=128K]
    Kernel driver in use: amdgpu
    Kernel modules: amdgpu

This definitely isn't working:

user@host:~$ cat lspciVGA

var1="$(lspci | grep -E "VGA|3D")"
var2="$(expr substr ${var1} 0 7)"
var3="$(sudo lspci -v -s ${var2})"
echo "$var3"


user@host:~$ bash lspciVGA
expr: syntax error
lspci: option requires an argument -- 's'
Usage: lspci []

Basic display modes:
-mm             Produce machine-readable output (single -m for an obsolete format)
-t              Show bus tree

Display options:
-v              Be verbose (-vv for very verbose)
-k              Show kernel drivers handling each device
-x              Show hex-dump of the standard part of the config space
-xxx            Show hex-dump of the whole config space (dangerous; root only)
-xxxx           Show hex-dump of the 4096-byte extended config space (root only)
-b              Bus-centric view (addresses and IRQ's as seen by the bus)
-D              Always show domain numbers

Resolving of device ID's to names:
-n              Show numeric ID's
-nn             Show both textual and numeric ID's (names & numbers)
-q              Query the PCI ID database for unknown ID's via DNS
-qq             As above, but re-query locally cached entries
-Q              Query the PCI ID database for all ID's via DNS

Selection of devices:
-s [[[[]:]]:][][.[]]   Show only devices in selected slots
-d []:[]                        Show only devices with specified ID's

Other options:
-i        Use specified ID database instead of /usr/share/misc/pci.ids.gz
-p        Look up kernel modules in a given file instead of default modules.pcimap
-M              Enable `bus mapping' mode (dangerous; root only)

PCI access options:
-A      Use the specified PCI access method (see `-A help' for a list)
-O =  Set PCI access parameter (see `-O help' for a list)
-G              Enable PCI access debugging
-H        Use direct hardware access ( = 1 or 2)
-F        Read PCI configuration dump from a given file

Reference: https://stackoverflow.com/questions/8928224/trying-to-retrieve-first-5-characters-from-string-in-bash-error

2 Answers 2


there is a problem in the assignment of var2. It should read:

var2=$(expr substr "${var1}" 1 7)

the reason for the quotes is that var1 has whitespaces that confuse substr, and the 0 -> 1 is because it starts counting from 1.

Also there are some problems with your quotes:


var1=$(lspci | grep -E "VGA|3D")
var2=$(expr substr "${var1}" 1 7)
var3=$(sudo lspci -v -s "${var2}")
echo "$var3"
  • It worked just updating quotes for second line (var2). Why is that? Can you only use quotes once per line? May 13, 2016 at 20:42
  • if you set var1 to i.e. 'hello world' then the command would become expr substr hello world 1 7 - resulting in error. With quotes 'hello world' is treated as a single argument.
    – user448115
    May 13, 2016 at 20:54

Using grep with PCRE (-P):

lspci | grep -Po '^\s*\K\S+(?=\s+VGA\s)'


lspci -v -s 00:01.0 | grep -Po '^\s*\K\S+(?=\s+VGA\s)'
  • ^\s* matches zero or more whitespaces at the start and \K discards the match, this is to tackle the second case where there are spaces at the start

  • \S+ matches any number of non-whitespace characters, this is our desired portion

  • The zero width positive lookahead pattern, (?=\s+VGA\s), ensures that the desired match is floowed by VGA after whitespaces after the desired portion.

To save the output in a variable, use command substitution ($()):

value=$(lspci | grep -Po '^\s*\K\S+(?=\s+VGA\s)')


value=$(lspci -v -s 00:01.0 | grep -Po '^\s*\K\S+(?=\s+VGA\s)')

Now you can get the value by $value.

Example (on my system):

$ lspci | grep -Po '^\s*\K\S+(?=\s+VGA\s)'

$ lspci -v -s 00:02.0 | grep -Po '^\s*\K\S+(?=\s+VGA\s)'
  • I like how you account for whitespace and view VGA a different way. This worked for me: user@host:~$ cat lspciVGA2 var1=$(lspci | grep -Po '^\s*\K\S+(?=\s+VGA\s)') var2=$(lspci -v -s "${var1}") echo "$var2" May 14, 2016 at 15:15
  • @conman253 Great..
    – heemayl
    May 14, 2016 at 16:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.