ファイルが引数として指定されているかどうかに応じて、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"
。