如何正确检索,使用bash' cut,文本文件中只有1个字段的第一个字段?

时间:2017-03-26 08:26:47

标签: cut gnu-coreutils

在带有(财务)帐户的文本文件(accounts.txt)中,子帐户是,并且需要用下划线分隔,如下所示:

assets
assets_hh
assets_hh_reimbursements
assets_hh_reimbursements_ff

......等等。

现在我想从特定的行号中获取特定的子帐户,例如: 第4行的第3栏:

$ lnr=4; fnr=3
$ cut -d $'\n' -f "$lnr" < accounts.txt | cut -d _ -f "$fnr"
reimbursements
$

但fnr = 1和fnr = 2都给出了第一行,它只有一个字段:

$ cut -d $'\n' -f 1 < accounts.txt | cut -d _ -f "fnr"
assets
$

这是不受欢迎的行为。

现在我可以通过在每个帐户前加下划线并为每个必需的字段编号添加1来解决这个问题,但这不是一个优雅的解决方案。 我做错了什么和/或可以通过发出不同的检索命令来改变它吗?

3 个答案:

答案 0 :(得分:2)

使用cut -d $'\n' -f "$lnr"从文件中获取lnr-th行有点奇怪。更常见的方法是使用sed,例如:

sed -n "${lnr}p" file | cmd ...

但是,为此,awk更好 - 在一次调用中也可以处理lnrfnr

file=accounts.txt
lnr=1
fnr=2
awk -F_ -v l=$lnr -v f=$fnr 'NR==l{print $f}' "$file"

以上所有组合lnr / fnr产生:

line                          field1   field2   field3           field4
------------------------------------------------------------------------
assets                        assets
assets_hh                     assets   hh
assets_hh_reimbursements      assets   hh       reimbursements
assets_hh_reimbursements_ff   assets   hh       reimbursements   ff

答案 1 :(得分:1)

检查以下解决方案 -

cat f
assets
assets_hh
assets_hh_reimbursements
assets_hh_reimbursements_ff

根据您的评论尝试以下命令 -

$ lnr=1; fnr=2
$ echo $lnr $fnr
1 2
$ awk -v lnr=$lnr -v fnr=$fnr  -F'_' 'NR==lnr  {print $fnr}' f
             ###Output is nothing as line 1 column 2 is blank when FS="_"
$ lnr=4;fnr=1
$ echo $lnr $fnr
4 1
$ awk -v lnr=$lnr -v fnr=$fnr  -F'_' 'NR==lnr  {print $fnr}' f
assets
$ lnr=4;fnr=3
$ echo $lnr $fnr
4 3
$ awk -v lnr=$lnr -v fnr=$fnr  -F'_' 'NR==lnr  {print $fnr}' f
reimbursements

答案 2 :(得分:0)

一个解决方案是将head|tailread放入数组中,以便更轻松地处理这些项目:

lnr=4
fnr=2
IFS=_ read -r -a arr < <(head -n "$lnr" accounts.txt | tail -n 1)
#note that the array is 0-indexed, so the fieldnumber has to fit that
echo "${arr[$fnr]}"

然后你可以将想法扩展为更有用的功能:

get_field_from_file() {
    local fname="$1"
    local lnr="$2"
    local fnr="$3"
    IFS=_ read -r -a arr < <(head -n "$lnr" "$fname" | tail -n 1)
    if (( $fnr > ${#arr[@]} )); then
        return 1
    else
        echo "${arr[$fnr]}"
    fi
}

field=$(get_field_from_file "accounts.txt" "4" "2") || echo "no such line or field"
[[ -n $field ]] && echo "field: $field"