1

次のawkコマンドを使用しています。

my_command | awk -F "[[:space:]]{2,}+" 'NR>1 {print $2}' | egrep "^[[:alnum:]]"

次のようにデータを正常に返します。

fileName1
file Name 1
file Nameone
f i l e Name 1

ご覧のとおり、一部のファイル名にはスペースが含まれています。ファイル名をエコーし​​ようとしているだけなので、これで問題ありません(特別なことは何もありません)。問題は、ループ内でその特定の行を呼び出すことです。私はこのようにしようとしています:

i=1
for num in $rows
do
  fileName=$(my_command | awk -F "[[:space:]]{2,}+" 'NR==$i {print $2}' | egrep "^[[:alnum:]])"
  echo "$num $fileName"
  $((i++))
done

しかし、私の出力は常にnull

私も使用しawk -v record=$iてから印刷しようとしまし$recordたが、以下の結果が得られました。

f i l e Name 1

編集

混乱して申し訳ありません: rowsは、このような ID をリストする変数で11 12 13 あり、これらの ID のそれぞれがファイル名に関連付けられています。解析を行わないコマンドは次のようになります。

     id      File Info      OS
     11      File Name1     OS1
     12      Fi leNa me2    OS2
     13      FileName 3     OS3

idフィールドを使用して必要なコマンドを実行することしかできませんが、フィールドを使用して、コマンドが実行されている File Info実際のことをユーザーに通知したいと考えています。File

4

4 に答える 4

2

シェル変数は、単一引用符で囲まれた文字列内では展開されません。オプションを使用して-v、awk 変数をシェル変数に設定します。

fileName=$(my_command | awk -v i=$i -F "[[:space:]]{2,}+" 'NR==i {print $2}' | egrep "^[[:alnum:]])"

このメソッドは、konsolebox の回答で必要とされるよう$に、スクリプト内のすべての文字をエスケープする必要を回避します。awk

于 2013-08-26T18:58:58.950 に答える
2

思うように$i伸びないと思います。引数を次のように引用する必要があります。

  fileName=$(my_command | awk -F "[[:space:]]{2,}+" "NR==$i {print \$2}" | egrep "^[[:alnum:]]")

そして、あなたはもう一方を忘れました)

編集

要件の更新として、ループ内で繰り返しコマンドを実行する代わりに、行を単一の awk コマンドに渡すことができます。

#!/bin/bash

ROWS=(11 12)

function my_command {
    # This function just emulates my_command and should be removed later.
    echo "     id      File Info      OS
     11      File Name1     OS1
     12      Fi leNa me2    OS2
     13      FileName 3     OS3"
}

awk -- '
    BEGIN {
        input = ARGV[1]
        while (getline line < input) {
            sub(/^ +/, "", line)
            split(line, a, /   +/)
            for (i = 2; i < ARGC; ++i) {
                if (a[1] == ARGV[i]) {
                    printf "%s %s\n", a[1], a[2]
                    break
                }
            }
        }
        exit
    }
' <(my_command) "${ROWS[@]}"

その awk コマンドは、次のように 1 行に要約できます。

awk -- 'BEGIN { input = ARGV[1]; while (getline line < input) { sub(/^ +/, "", line); split(line, a, /   +/); for (i = 2; i < ARGC; ++i) { if (a[1] == ARGV[i]) {; printf "%s %s\n", a[1], a[2]; break; }; }; }; exit; }' <(my_command) "${ROWS[@]}"

または、代わりに Bash 全体を使用することをお勧めします。

#!/bin/bash

ROWS=(11 12)

while IFS=$' ' read -r LINE; do
    IFS='|' read -ra FIELDS <<< "${LINE//  +( )/|}"
    for R in "${ROWS[@]}"; do
        if [[ ${FIELDS[0]} == "$R" ]]; then
            echo "${R} ${FIELDS[1]}"
            break
        fi
    done
done < <(my_command)

次のような出力が得られるはずです。

11 File Name1
12 Fi leNa me2
于 2013-08-26T18:57:47.077 に答える
1

出力から 1 行を抽出するためだけに、ループを毎回再実行my_command(および)するのはかなり非効率的です。awk特に、各行の一部を順番に印刷するだけの場合はなおさらです。my_command(実際にはまったく同じコマンドであり、ループを実行するたびに同じ出力が生成されると想定しています。)

その場合、このワンライナーでうまくいくはずです:

paste -d' ' <(printf '%s\n' $rows) <(my_command | 
  awk -F '[[:space:]]{2,}+' '($2 ~ /^[::alnum::]/) {print $2}')
于 2013-08-26T19:16:12.113 に答える