diff --git a/src/uu/lscpu/src/lscpu.rs b/src/uu/lscpu/src/lscpu.rs
index 2fc84cf..21cb5c6 100644
--- a/src/uu/lscpu/src/lscpu.rs
+++ b/src/uu/lscpu/src/lscpu.rs
@@ -52,46 +52,101 @@ impl CpuInfos {
     }
 }
 
+struct OutputOptions {
+    json: bool,
+    _hex: bool,
+}
+
 #[uucore::main]
 pub fn uumain(args: impl uucore::Args) -> UResult<()> {
     let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
 
     let system = System::new_all();
 
-    let _hex = matches.get_flag(options::HEX);
-    let json = matches.get_flag(options::JSON);
+    let output_opts = OutputOptions {
+        _hex: matches.get_flag(options::HEX),
+        json: matches.get_flag(options::JSON),
+    };
 
     let mut cpu_infos = CpuInfos::new();
-    cpu_infos.push("Architecture", &get_architecture(), None);
     cpu_infos.push("CPU(s)", &format!("{}", system.cpus().len()), None);
     // Add more CPU information here...
 
-    if let Ok(contents) = fs::read_to_string("/proc/cpuinfo") {
-        if let Some(cpu_model) = find_cpuinfo_value(&contents, "model name") {
-            if let Some(addr_sizes) = find_cpuinfo_value(&contents, "address sizes") {
-                cpu_infos.push(
-                    "Model name",
-                    cpu_model.as_str(),
-                    Some(vec![CpuInfo {
-                        field: "Address sizes".to_string(),
-                        data: addr_sizes,
-                        children: vec![],
-                    }]),
-                );
-            } else {
-                cpu_infos.push("Model name", cpu_model.as_str(), None);
+    let contents = match fs::read_to_string("/proc/cpuinfo") {
+        // Early return if we can't read /proc/cpuinfo for whatever reason
+        // TODO: Should this return an non-zero exit code to user, or do we just ignore it and display whatever CPU info we could find?
+        Err(_) => return Ok(()),
+        Ok(contents) => contents,
+    };
+
+    let mut arch_children: Vec<CpuInfo> = vec![];
+
+    if let Some(addr_sizes) = find_cpuinfo_value(&contents, "address sizes") {
+        arch_children.push(CpuInfo {
+            field: "Address sizes".to_string(),
+            data: addr_sizes,
+            children: vec![],
+        })
+    }
+
+    cpu_infos.push("Architecture", &get_architecture(), Some(arch_children));
+
+    // TODO: This is currently quite verbose and doesn't strictly respect the hierarchy of `/proc/cpuinfo` contents
+    // ie. the file might contain multiple sections, each with their own vendor_id/model name etc. but right now
+    // we're just taking whatever our regex matches first and using that
+    if let Some(vendor) = find_cpuinfo_value(&contents, "vendor_id") {
+        let mut vendor_children: Vec<CpuInfo> = vec![];
+
+        if let Some(model_name) = find_cpuinfo_value(&contents, "model name") {
+            let mut model_children: Vec<CpuInfo> = vec![];
+
+            if let Some(family) = find_cpuinfo_value(&contents, "cpu family") {
+                model_children.push(CpuInfo {
+                    field: "CPU Family".to_string(),
+                    data: family,
+                    children: vec![],
+                });
             }
+
+            if let Some(model) = find_cpuinfo_value(&contents, "model") {
+                model_children.push(CpuInfo {
+                    field: "Model".to_string(),
+                    data: model,
+                    children: vec![],
+                });
+            }
+
+            vendor_children.push(CpuInfo {
+                field: "Model name".to_string(),
+                data: model_name,
+                children: model_children,
+            });
+        }
+        cpu_infos.push("Vendor ID", vendor.as_str(), Some(vendor_children));
+    }
+
+    print_output(cpu_infos, output_opts);
+
+    Ok(())
+}
+
+fn print_output(infos: CpuInfos, out_opts: OutputOptions) {
+    if out_opts.json {
+        println!("{}", infos.to_json());
+        return;
+    }
+
+    // Recursive function to print nested CpuInfo entries
+    fn print_entries(entries: Vec<CpuInfo>, depth: usize, _out_opts: &OutputOptions) {
+        let indent = "  ".repeat(depth);
+        for entry in entries {
+            // TODO: Align `data` values to form a column
+            println!("{}{}: {}", indent, entry.field, entry.data);
+            print_entries(entry.children, depth + 1, _out_opts);
         }
     }
 
-    if json {
-        println!("{}", cpu_infos.to_json());
-    } else {
-        for elt in cpu_infos.lscpu {
-            println!("{}: {}", elt.field, elt.data);
-        }
-    }
-    Ok(())
+    print_entries(infos.lscpu, 0, &out_opts);
 }
 
 fn find_cpuinfo_value(contents: &str, key: &str) -> Option<String> {
@@ -101,11 +156,11 @@ fn find_cpuinfo_value(contents: &str, key: &str) -> Option<String> {
         .build()
         .unwrap();
 
-    if let Some(cap) = re.captures_iter(contents).next() {
-        return Some(cap[1].to_string());
-    };
-
-    None
+    let value = re
+        .captures_iter(contents)
+        .next()
+        .map(|cap| cap[1].to_string());
+    value
 }
 
 fn get_architecture() -> String {
@@ -137,6 +192,7 @@ pub fn uu_app() -> Command {
         )
         .arg(
             Arg::new(options::JSON)
+                .short('J')
                 .long("json")
                 .help(
                     "Use JSON output format for the default summary or extended output \