3

我发现了几个关于如何将变量从bashinto传递的问题awk,最值得注意的是-v命令,但我似乎无法让它们做我想做的事。

在脚本之外,我正在运行的命令是

awk '$2 ~ /^\/var$/ { print $1 }' /etc/fstab

它只搜索/etc/fstab分区/var,并且应该打印出物理安装点,或者如果没有,则什么都没有。

现在在脚本中,我有一个包含许多分区的数组,我想做的是遍历该数组以搜索 fstab 中的每个物理挂载点。问题在于数组中的元素有一个/

所以我想做的(在非常不正确的awk中)是:

PARTITIONS=(/usr /home /var tmp);
for ((n=0; n<${#PARTITION[@]}; n++)); do
    cat /etc/fstab | awk '$2 ~ /^\${PARTITIONS[$n]}$/ { print $1 }';
done

但我知道那是不正确的。我现在最接近的是:

PARTITIONS=(/usr /home /var tmp);
for ((n=0; n<${#PARTITION[@]}; n++)); do
    cat /etc/fstab | awk -v partition="${PARTITIONS[$n]}" '$2 ~ /^\/var$/ { print $1," ",partition }';
done

哪个至少将分区变量放入 awk,但根本无法帮助我匹配它。

所以基本上,我需要输入阵列,然后取出物理分区。最终结果将被分配给另一个数组,但是一旦我得到输出,我就可以从那里开始。

我也知道 awk 可以在一开始就消除对 cat 的需求,但是我对 awk 的了解还不够。:)

谢谢你的帮助。

编辑

cat /etc/fstab | awk -v partition="${PARTITIONS[$n]}" '$2 ~ partition { print $1 }'

近似于我需要的足够有用的东西。我显然过于关注包含正则表达式。如果其他人可以清理它,将不胜感激:)

4

6 回答 6

2
awk -v partition="${partitions[$n]}" '$2 ~ "^/" partition "$" { print $1 }' /etc/fstab

您可以连接正则表达式字符(^- 字符串开头和$- 字符串结尾)和作为分区名称一部分的斜杠和包含分区名称的变量,方法是将它们彼此相邻放置。您不需要使用分隔硬编码正则表达式的斜线。

AWK 将接受文件名作为参数,而不使用cat管道或<重定向它。

我建议习惯于在 shell 中使用混合或小写的变量名,以避免与 shell 或环境变量的潜在名称冲突。

于 2012-07-14T20:19:56.790 回答
2

您还可以将整个数组传递给awkthrough -v,这假定目录名称不包含空格:

PARTITIONS=(/usr /home /var /tmp)
awk -v partition="${PARTITIONS[*]}" \
  '$2 != "" && partition ~ $2"\\>" { print $1 }' /etc/fstab

这避免了for循环的需要。

解释

  • `partition="${PARTITIONS[*]}" 将整个数组作为空格分隔的字符串传递。
  • $2 != ""表示没有空行匹配。
  • partition ~ $2"\\>"匹配$2传入的字符串,\\>要求匹配位于单词的末尾。
于 2012-07-14T20:37:32.797 回答
1

首先,为了摆脱最烦人的事情(GUoC),awk可以像处理文件一样工作cat,所以直接传递它。您不能通过未展平的方式传递整个数组-v,但由于您正在迭代项目,所以没关系。如果你想避免-v,你可以通过直接将它们包含到 awk 脚本中来传递 bash 变量,你只需要小心引用(空格和 awk 自己的 $variable 用法)。例子:

awk '$2 ~ "'${PARTITIONS[$n]}'" { print $1 }' /etc/fstab

或者带有软引号的更复杂的版本:

awk "\$2 ~ /${PARTITIONS[$n]//\//\\/}/ { print \$1 }" /etc/fstab
于 2012-07-14T20:11:41.243 回答
1

您可以使用 bash 的进程替换将数组作为附加文件传递给 awk。

partitions=( /usr /home /var /tmp )
awk '
    FNR==NR { partitions[$0]=""; next } 
    $1 !~ /^#/ && ($2 in partitions) { print $1 }
' <(printf '%s\n' "${partitions[@]}") /etc/fstab

NR 保存当前读取的记录(行)数,FNR 保存当前文件中读取的当前记录数,所以 FNR==NR 只有在读取第一个文件时才成立,也就是本例中的进程替换。所以你填充了第一个文件的分区数组。

然后,对于第二个文件,您只需检查第二个字段是否在数组中......

不过,在这种情况下,我只使用 bash(版本 >= 4.0),因为/etc/fstab它通常相当小。

declare -A 'partitions=([/usr]= [/home]= [/var]= [/tmp]=)'
while read -r spec file vfstype mntops freq passno; do
    [[ $spec != \#* && ${partitions[$file]+set} ]] && echo "$spec"
done < /etc/fstab

或者根据实际目标,您可以 parse df,它会告诉您目录所在的文件系统。

dirs=( /usr /home /var /tmp )
for dir in "${dirs[@]}"; do
    { read -r; read -r part _; } < <(df -P "$dir")
    echo "$part"
done
于 2012-07-14T20:35:32.100 回答
0

你可以这样做:

awk -v partitions="${PARTITIONS[*]}" '
    BEGIN { split(partitions,a," ") }
    { for (e in a) { if ($2 ~ a[e]) { print $1 } } }' /etc/fstab 

因此,您无需在for外部创建循环awk,这意味着更少的流程。

于 2012-07-14T20:10:29.783 回答
0

以下是一些可能有所帮助的观察结果。

如果输入只是一个文件,则不需要cat任何内容​​。那是:

$ cat file | program # would normally just be ...
$ program < file

如果您需要将一些复杂的东西提供给awk(1),那么也许您确实有一个用例cat x | y... 您可以执行类似 ...

(echo StartFlag ${PARTITIONS[*]}; cat /etc/fstab) | awk ...

最后,为了在 SO 上获得最佳结果,请以如下格式询问...

  1. 我的 PARTITIONS bash 变量包含简化的示例内容
  2. 假设我的 /etc/fstab 包含简化的示例 fstab
  3. 如何获得以下输出:基于简化输入的确切期望输出
  4. 这就是我尝试过的:有些人不仅会提供代码,还有助于在您试图找到解决方案的特定编程问题上寻求帮助
于 2012-07-14T20:12:07.677 回答