我正在尝试根据文件是否作为参数给出来运行 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"
.