在 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”(它运行两次,这是根据数据预期的),但 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

编辑:显然有东西正在消耗标准输入,虽然我无法进入调试模式(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一点时,已经没有什么可以消耗的了。我无法弄清楚你的脚本应该做什么,因为你给出的输出似乎不是来自输入,但是使 awk 在文件(如果存在)或 stdin(如果不存在)上工作的一个简单方法是使用多变的:

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".

相关内容