How to Capture First Column Values of a Command?

I am new to shell scripting. I am trying to write a script that is suppose to run a command and use for loop to capture first column of the output and do further processing.

command: tst get files

output of this command is something like

NAME        COUNT           ADMIN
FileA.txt   30              adminA
FileB.txt   21              local
FileC.txt   9               local
FileD.txt   90              adminA

Here is what I have tried so far : UPDATED also want to run additional commands

#!/bin/bash

for f in $(tst get files)
do
    echo "FILE :[${f}]"
    tst setprimary ${f} && tst get dataload
done

the output I am seeing is something like

FILE :[NAME]
FILE :[COUNT]
FILE :[ADMIN]
FILE :[FileA.txt]
FILE :[30]
FILE :[adminA]
FILE :[FileB.txt]
FILE :[21]
FILE :[local]
FILE :[FileC.txt]
FILE :[9]
FILE :[local]
FILE :[FileD.txt]
FILE :[90]
FILE :[adminA]

I am looking for an output something like

FILE :[FileA.txt]
FILE :[FileB.txt]
FILE :[FileC.txt]
FILE :[FileD.txt]

What should I modify in the shell script to only capture NAME column values? Am I executing the tst get files command correctly in the for loop or is there a better way to execute a command and loop thru the results?

3 Answers

EDIT (Samuel Kirschner): you can do without the for loop entirely and just use awk to print the lines you're interested in

tst get files | awk 'NR > 1 {print "FILE :[" $1 "]"}'

If you want to keep the for loop for some reason and just extract the file name from the lines while skipping the header, you have a few choices. Awk is probably the easiest because of the NR builtin variable (which counts lines) and automatic field-splitting ($1 refers to the first field in the line, for instance), but you can use sed and cut as well.

You can use awk 'NR > 1 {print $1}' to get the first column (using any whitespace character as a delimiter while skipping the first line) or sed 1d | cut -d$'\t' -f1. Note that $'\t' is bash-specific syntax for a literal tab character, if your file is padded with spaces rather than using tabs to delimit fields, you can't use the sed ... | cut ... example.

i.e.

#!/bin/bash

for f in $(tst get files | awk 'NR > 1 {print $1}')
do
    echo "FILE :[${f}]"
done

or

#!/bin/bash

for f in $(tst get files | sed 1d | cut -d$'\t' -f1)
do
    echo "FILE :[${f}]"
done

to avoid unnecessary splitting in the for loop. It's best to set IFS to something specific outside the loop body to prevent 'a file with whitespace.txt' from being broken up.

OLD_IFS=IFS
IFS=$'\n\t'

for f in $(tst get files | sed 1d | cut -d$'\t' -f1)
do
    echo "FILE :[${f}]"
done
2

You can just do:

tst get files | awk 'NR > 1 { printf "FILE :[%s]\n", $1 }'

Update: To answer extended problem as per comments below by OP:

while read -r file _; do
    tst setprimary "$file" && tst get dataload 
done < <(tst get files)
6

Or perl:

tst ... | perl -lanE 'say "File: [$F[0]]" if $.>1'
  • the variable $. contains the current line number

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Maya Lin-Takahashi

Maya Lin-Takahashi

Consumer Tech & Gadget Reviewer

Maya is a hardware enthusiast who tests and reviews smart home devices, smartphones, wearables, and audio gear. She focuses on practical consumer value and build quality.

Share this article
Twitter Facebook Pinterest