从输入输出每 N 列

Rad*_* Rk 5 shell-script text-processing

我正在尝试编写一个脚本,通过将起始列、增量值和文件名作为运行时参数来打印文件的每 N 列。下面是我的脚本:

file=$1
st=$2
inc=$3

echo $file
echo $st
echo $inc

awk '{for (i = $st; i <= NF; i += $inc) printf ("%s%c", $i, i + $inc <= NF ? " " : "\n");}' $file
Run Code Online (Sandbox Code Playgroud)

我无法得到结果。任何人都可以帮助我吗?我的输入可以像script.sh file_name 1 4

提前致谢。:-)

Sté*_*las 9

壳牌变量不会自动地成为awk变量(也awk,变量表示var,不$var也就是var领域)。如果要将 shell 变量传递给awk,一个简单的方法是使用环境:

#! /bin/sh -
file=$1
ST=$2
INC=$3

export ST INC
awk '
  {
    sep = ""
    for (i = ENVIRON["ST"]; i <= NF; i += ENVIRON["INC"]) {
      printf "%c%s", sep, $i
      sep = OFS
    }
    printf "\n"
  }' < "$file"
Run Code Online (Sandbox Code Playgroud)

请记住引用您的 shell 变量,awk并且不能将任意文件名作为参数(因为它会处理其中一些带有 a=-专门调用的文件名)。

将变量传递给的另一种方法awk是在 awk 脚本之后使用-v awkvar="$shellvar"awkvar="$shellvar"参数,但这些不能用于任意字符串,因为转义序列在其中展开(例如\\变成\\n变成换行符)和 GNU awk4.2 或更高版本,@//除非在 POSIX 模式下,否则开头和结尾的会被特殊对待

awk -v st="$st" -v inc="$inc" '{for (i = st; i <= NF; i += inc)...}' < "$file"
Run Code Online (Sandbox Code Playgroud)

或者

awk  '{for (i = st; i <= NF; i += inc)...}' st="$st" inc="$inc" < "$file"
Run Code Online (Sandbox Code Playgroud)

在这里没问题,因为这些变量只包含数字(所以没有反斜杠)。

无论你做什么,不要做:

awk 'for (i = '"$st"'; i <= NF; i += '"$inc"')...'
Run Code Online (Sandbox Code Playgroud)

更别说

awk 'for (i = '$st'; i <= NF; i += '$inc')...'
Run Code Online (Sandbox Code Playgroud)

那就是让 shell 扩展传递给 的代码中$st$inc变量的值awk,因为这会产生命令注入漏洞(例如对于stlike 的值system("reboot"))。