stdinでawkを実行すると機能しません。

stdinでawkを実行すると機能しません。

ファイルが引数として指定されているかどうかに応じて、awkコマンドを実行しようとしています。それ以外の場合は、次のようにstdinで実行します。

 38 for index in "${line_numbers[@]}"; do
 39    if [ -n "$file" ]; then
 40       echo "hi"
 41       cat "$file" | awk -v idx="$index" -v col="$column" -v value="$value" -F ',' '{if (idx==NR) {for(i=1;i<=NF;i++) {    if (i==col) $i=value; printf("%s%s", $i, (i==NF ? "\n":FS))}}}'
 42    else
 43       echo "bye"
 44       awk -v col="$column" -v idx="$index" -v value="$value" -F ',' '{if (idx==NR) {for(i=1;i<=NF;i++) {if (i==col) $i    =value; printf("%s%d%s", $i, i, (i==NF ? "\n":FS))}}}'
 45    fi
 46 done

ファイルを読むにはgetoptsを使用してください(しかし、次のタスクを実行するためにstdinに頼っているので、それは重要ではありませんが、このコードに言及する必要があると思いました)。

  3 file=""
  4 unset -v number column value  
  5 cmd="echo"
  6 
  7 while getopts f:n:c:v: opt; do
  8    case $opt in
  9       f) file="$OPTARG";;
 10       n) number="$OPTARG";;
 11       c) column="$OPTARG";;
 12       v) value="$OPTARG";;
 13       *) printf>&2 '%s\n' "Usage: $0 [-f file] [-n number] [-c column] [-v value]";;
 14    esac
 15 done

ただし、forループの出力は「bye」の後に「bye」(データによって予想される2回実行されます)ですが、awkコマンドはまったく実行されません。

stdinがコマンドで使用されるデフォルト値であるという印象を受けましたが、awkコマンドは私がテストしたように何かを出力する必要がありますが、何も実行しません。

elseブロックのawkコマンドが実行されない理由をご存知ですか?

私が実行するコマンドは次のとおりです。

cat data.csv | ./update.sh -n 444 -c 2 -v " Alex"

データは次のとおりです

444-555-7777, Max,Weaver, personal:friend:musician
111-222-6665, Craig,Kowalick,office:friend
888-797-2345,Tom, O’Brien, personal:family:musician:midnightsociety
444433443,fgdfg,gdfg,fdgdfgf:test:test:test2

したがって、出力は次のようになります。

444-555-7777, Alex,Weaver, personal:friend:musician
444433443, Alex,gdfg,fdgdfgf:test:test:test2

編集:明らかに何かがstdinを消費していますが、デバッグモードに入ることはできませんが(vimが認識しないと言います:set -x)、私のスクリプトは次のようになります。

#!/bin/bash

my_stdin=$(cat)

file=""
unset -v number column value  
cmd="echo"

while getopts f:n:c:v: opt; do
    case $opt in
        f) file="$OPTARG";;
        n) number="$OPTARG";;
        c) column="$OPTARG";;
        v) value="$OPTARG";;
        *) printf>&2 '%s\n' "Usage: $0 [-f file] [-n number] [-c column] [-v value]";;
    esac
done

shift $((OPTIND-1))

if [ "$column" -gt 4 ] || [ "$column" -lt 1 ]; then
       echo "this script can only handle cols1-4. for group editing, try ./groups.sh"
       exit 1
fi       

declare -a line_numbers

grep_output=$(grep -n "$number" <<< "$my_stdin" | cut -d: -f1)

if [ -n "$file" ]; then
    grep_output="$(cat "$file" | grep -n "$number" | cut -d: -f1)"
fi

echo "$grep_output"

IFS=$'\n' read -d '' -ra line_numbers <<< "$grep_output"

for index in "${line_numbers[@]}"; do
    if [ -n "$file" ]; then
        echo "hi"
        cat "$file" | awk -v idx="$index" -v col="$column" -v value="$value" -F ',' '{if (idx==NR) {for(i=1;i<=NF;i++) {if (i==col) $i=value; printf("%s%s", $i, (i==NF ? "\n":FS))}}}' "${@:--}"
    else
        awk -v col="$column" -v idx="$index" -v value="$value" -F ',' '{if (idx==NR) {for(i=1;i<=NF;i++) {if (i==col) $i=value; printf("%s%s", $i, (i==NF ? "\n":FS))}}}' <<< "$my_stdin"
    fi
done

echo

exit 0

ベストアンサー1

この行は標準入力を使用します。

grep_output="$(grep -n "b" )"

したがって、このポイントに達するまでにawk消費するものは何も残りません。あなたが提供する出力が入力からのものではないように見えますが、ファイル(存在する場合)またはstdin(存在する場合)でawk操作を実行する簡単な方法なので、スクリプトが何をすべきかはわかりません。存在しない)変更可能を使用することです。

awk 'awk command here' "$file"

これを説明するために、次の簡単なスクリプトを検討してください。

#!/bin/bash

awk '{ print $1 }' "$1"

引数を使用して実行すると、設定されて$1読み取ろawkうとします。

$ echo "foo" > file.txt
$ foo.sh file.txt
foo

引数なしで実行すると、STDINから読み込まれます。

$ cat file.txt | foo.sh
foo

今私考えるあなたが望むのは、与えられた数字で始まるすべての行に与えられた列の値を変更することです。その場合、スクリプト全体を次のように単純化できます。

#!/bin/bash

while getopts f:n:c:v: opt; do
    case $opt in
        f) file="$OPTARG";;
        n) number="$OPTARG";;
        c) column="$OPTARG";;
        v) value="$OPTARG";;
        *)
          printf>&2 '%s\n' "Usage: $0 [-f file] [-n number] [-c column] [-v value]"
          ;;
    esac
done


## You probably want to set up the same set of checks for the other required fields
if [ -z "$column" ]; then
  echo "Please specify a column number with -c." >&2
  exit 1
elif [[ ! "$column" =~ ^[0-9][0-9]*$ ]]; then
  echo "Column value '$column' is invalid. Please use a number from 1 to 4." >&2
  exit 1
elif [ "$column" -gt 4 ] || [ "$column" -lt 1 ]; then
       echo "this script can only handle cols1-4. for group editing, try ./groups.sh" >&2
       exit 1
fi       

## The trick here is setting num to ^$number so we can
## then use it as a regex matching the beginning of the line
awk -v num="^$number" -v col="$column" -v value="$value" -F ',' \
    'BEGIN{OFS=FS}{ if ($0 ~ num) { $col=value; print }}' "$file"

これで必要に応じて実行できます。

$ cat data.csv | foo.sh -n 444 -c 2 -v " Alex"
444-555-7777, Alex,Weaver, personal:friend:musician
444433443, Alex,gdfg,fdgdfgf:test:test:test2

$ foo.sh -n 444 -c 2 -v " Alex" -f data.csv 
444-555-7777, Alex,Weaver, personal:friend:musician
444433443, Alex,gdfg,fdgdfgf:test:test:test2

ファイルのどこにでもgrep一致します。444それがあなたが望むものなら、num="$number"代わりに使用してくださいnum="^$number"

おすすめ記事