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

편집: 분명히 뭔가가 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".

관련 정보