为什么双引号在 awk 脚本中 cmd 内的 echo 语句中不起作用?
Why double quote does not work in echo statement inside cmd in awk script?
gawk 'BEGIN { FS="|"; OFS="|" }NR ==1 {print} NR >=2 {cmd1="echo -n "" | base64 -w 0";cmd1 | getline d1;close(cmd1); print ,d1 }' dummy2.txt
输入:
id|dummy
1|subhashree:1;user=phn
2|subha:2;user=phn
预期输出:
id|dummy
1|c3ViaGFzaHJlZToxO3VzZXI9cGhuCg==
2|c3ViaGE6Mjt1c2VyPXBobgo=
脚本产生的输出:
id|dummy
1|subhashree:1
2|subha:2
我明白是 $2 左右的双引号导致了这个问题。它不起作用,因此没有正确编码字符串,只是在 semi colon.Because 之后剥离字符串它确实在分号内工作并在终端中提供正确的输出。
echo "subhashree:1;user=phn" | base64
c3ViaGFzaHJlZToxO3VzZXI9cGhuCg==
[root@DERATVIV04 encode]# echo "subha:2;user=phn" | base64
c3ViaGE6Mjt1c2VyPXBobgo=
我已经尝试在 awk 中使用单引号和双引号进行不同的变体,但它没有work.Any帮助将不胜感激。
非常感谢。
您现有的cmd1
生产
echo -n subhashree:1;user=phn | base64 -w 0
^ semicolon is there
所以如果你执行下面会产生
$ echo -n subhashree:1;user=phn | base64 -w 0
subhashree:1
带引号
$ echo -n 'subhashree:1;user=phn' | base64 -w 0
c3ViaGFzaHJlZToxO3VzZXI9cGhu
解决方法就是在 echo -n '<your-string>' | base64 -w 0
之前使用引号
$ cat file
id|dummy
1|subhashree:1;user=phn
2|subha:2;user=phn
$ gawk -v q="'" 'BEGIN { FS="|"; OFS="|" }NR ==1 {print} NR >=2 {cmd1="echo -n " q q" | base64 -w 0"; cmd1 | getline d1;close(cmd1); print ,d1 }' file
id|dummy
1|c3ViaGFzaHJlZToxO3VzZXI9cGhu
2|c3ViaGE6Mjt1c2VyPXBobg==
可以简化如下
gawk -v q="'" 'BEGIN {
FS=OFS="|"
}
NR==1{
print;
next
}
{
cmd1="echo -n " q q" | base64 -w 0";
print ((cmd1 | getline d1)>0)? OFS d1 : [=14=];
close(cmd1);
}
' file
基于Ed Morton recommendation http://awk.freeshell.org/AllAboutGetline
if/while ( (getline var < file) > 0)
if/while ( (command | getline var) > 0)
if/while ( (command |& getline var) > 0)
问题是因为在 shell 上下文中尝试 运行 echo
命令时缺少引号。你要做的基本上是转换成
echo -n subhashree:1;user=phn | base64 -w 0
shell 执行的两个命令由 ;
分隔,即 user=phn | base64 -w 0
表示赋值后跟管道,管道为空,因为赋值不会产生任何结果base64
的标准输入用于编码。另一段 subhashree:1
只是回显出来,它存储在您的 getline
变量 d1
.
中
解决问题的正确方法应该是使用引号
echo -n "subhashree:1;user=phn" | base64 -w 0
当你说你在 </code> 上使用引号时,这实际上是不正确的,引号实际上是在 <code>awk
的上下文中用于连接 cmd
字符串,即"echo -n "
、</code> 和 <code>" | base64 -w 0"
只是连接在一起。建议的双引号需要在 shell.
的上下文中
所以有了那个和其他一些修复,你的 awk
命令应该在下面。添加 gsub()
以删除尾随空格,这些空格出现在您显示的输入中。还使用了 printf
而不是回显。
awk -v FS="|" '
BEGIN {
OFS = FS
}
NR == 1 {
print
}
NR >= 2 {
gsub(/[[:space:]]+/, "", )
cmd = "printf \"%s\" \"" "\" | base64 -w 0"
if ((cmd | getline result) > 0) {
= result
}
close(cmd)
print
}
' file
所以对于上面的命令,你的命令执行如下,这将产生正确的结果。
printf "%s" "subhashree:1;user=phn" | base64 -w 0
您已经得到解释如何为此使用 awk 的答案,但您还应该考虑不为此使用 awk。排序调用其他命令(例如 bas64
)的工具是 shell,而不是 awk。您在调用方面尝试做的是:
shell { awk { loop_on_input { shell { base64 } } } }
而如果您直接从 shell 调用 base64
,它只是:
shell { loop_on_input { base64 } }
请注意,awk 命令每行输入生成一个新的子shell一次,而来自 shell 的直接调用则不会。
例如:
#!/usr/bin/env bash
file='dummy2.txt'
head -n 1 "$file"
while IFS='|' read -r id dummy; do
printf '%s|%s\n' "$id" "$(base64 -w 0 <<<"$dummy")"
done < <(tail -n +2 "$file")
这是由 awk -v n=100 'NR==1{print; next} {for (i=1;i<=n;i++) print}' dummy2.txt > file100
创建的每条数据行重复 100 次的输入文件的执行速度差异
$ ./tst.sh file100
Awk:
real 0m23.247s
user 0m3.755s
sys 0m10.966s
Shell:
real 0m14.512s
user 0m1.530s
sys 0m4.776s
以上时间是由运行这个命令产生的(答案中发布的两个awk脚本的时间大致相同,所以我只是随机选择了一个):
#!/usr/bin/env bash
doawk() {
local file=""
gawk -v q="'" 'BEGIN {
FS=OFS="|"
}
NR==1{
print;
next
}
{
cmd1="echo -n " q q" | base64 -w 0";
print ((cmd1 | getline d1)>0)? OFS d1 : [=14=];
close(cmd1);
}
' "$file"
}
doshell() {
local file=""
head -n 1 "$file"
while IFS='|' read -r id dummy; do
printf '%s|%s\n' "$id" "$(base64 -w 0 <<<"$dummy")"
done < <(tail -n +2 "$file")
}
# Use 3rd-run timing to eliminate cache-ing as a factor
doawk "" >/dev/null
doawk "" >/dev/null
echo "Awk:"
time doawk "" >/dev/null
echo ""
doshell "" >/dev/null
doshell "" >/dev/null
echo "Shell:"
time doshell "" >/dev/null
gawk 'BEGIN { FS="|"; OFS="|" }NR ==1 {print} NR >=2 {cmd1="echo -n "" | base64 -w 0";cmd1 | getline d1;close(cmd1); print ,d1 }' dummy2.txt
输入:
id|dummy
1|subhashree:1;user=phn
2|subha:2;user=phn
预期输出:
id|dummy
1|c3ViaGFzaHJlZToxO3VzZXI9cGhuCg==
2|c3ViaGE6Mjt1c2VyPXBobgo=
脚本产生的输出:
id|dummy
1|subhashree:1
2|subha:2
我明白是 $2 左右的双引号导致了这个问题。它不起作用,因此没有正确编码字符串,只是在 semi colon.Because 之后剥离字符串它确实在分号内工作并在终端中提供正确的输出。
echo "subhashree:1;user=phn" | base64
c3ViaGFzaHJlZToxO3VzZXI9cGhuCg==
[root@DERATVIV04 encode]# echo "subha:2;user=phn" | base64
c3ViaGE6Mjt1c2VyPXBobgo=
我已经尝试在 awk 中使用单引号和双引号进行不同的变体,但它没有work.Any帮助将不胜感激。
非常感谢。
您现有的cmd1
生产
echo -n subhashree:1;user=phn | base64 -w 0
^ semicolon is there
所以如果你执行下面会产生
$ echo -n subhashree:1;user=phn | base64 -w 0
subhashree:1
带引号
$ echo -n 'subhashree:1;user=phn' | base64 -w 0
c3ViaGFzaHJlZToxO3VzZXI9cGhu
解决方法就是在 echo -n '<your-string>' | base64 -w 0
$ cat file
id|dummy
1|subhashree:1;user=phn
2|subha:2;user=phn
$ gawk -v q="'" 'BEGIN { FS="|"; OFS="|" }NR ==1 {print} NR >=2 {cmd1="echo -n " q q" | base64 -w 0"; cmd1 | getline d1;close(cmd1); print ,d1 }' file
id|dummy
1|c3ViaGFzaHJlZToxO3VzZXI9cGhu
2|c3ViaGE6Mjt1c2VyPXBobg==
可以简化如下
gawk -v q="'" 'BEGIN {
FS=OFS="|"
}
NR==1{
print;
next
}
{
cmd1="echo -n " q q" | base64 -w 0";
print ((cmd1 | getline d1)>0)? OFS d1 : [=14=];
close(cmd1);
}
' file
基于Ed Morton recommendation http://awk.freeshell.org/AllAboutGetline
if/while ( (getline var < file) > 0)
if/while ( (command | getline var) > 0)
if/while ( (command |& getline var) > 0)
问题是因为在 shell 上下文中尝试 运行 echo
命令时缺少引号。你要做的基本上是转换成
echo -n subhashree:1;user=phn | base64 -w 0
shell 执行的两个命令由 ;
分隔,即 user=phn | base64 -w 0
表示赋值后跟管道,管道为空,因为赋值不会产生任何结果base64
的标准输入用于编码。另一段 subhashree:1
只是回显出来,它存储在您的 getline
变量 d1
.
解决问题的正确方法应该是使用引号
echo -n "subhashree:1;user=phn" | base64 -w 0
当你说你在 </code> 上使用引号时,这实际上是不正确的,引号实际上是在 <code>awk
的上下文中用于连接 cmd
字符串,即"echo -n "
、</code> 和 <code>" | base64 -w 0"
只是连接在一起。建议的双引号需要在 shell.
所以有了那个和其他一些修复,你的 awk
命令应该在下面。添加 gsub()
以删除尾随空格,这些空格出现在您显示的输入中。还使用了 printf
而不是回显。
awk -v FS="|" '
BEGIN {
OFS = FS
}
NR == 1 {
print
}
NR >= 2 {
gsub(/[[:space:]]+/, "", )
cmd = "printf \"%s\" \"" "\" | base64 -w 0"
if ((cmd | getline result) > 0) {
= result
}
close(cmd)
print
}
' file
所以对于上面的命令,你的命令执行如下,这将产生正确的结果。
printf "%s" "subhashree:1;user=phn" | base64 -w 0
您已经得到解释如何为此使用 awk 的答案,但您还应该考虑不为此使用 awk。排序调用其他命令(例如 bas64
)的工具是 shell,而不是 awk。您在调用方面尝试做的是:
shell { awk { loop_on_input { shell { base64 } } } }
而如果您直接从 shell 调用 base64
,它只是:
shell { loop_on_input { base64 } }
请注意,awk 命令每行输入生成一个新的子shell一次,而来自 shell 的直接调用则不会。
例如:
#!/usr/bin/env bash
file='dummy2.txt'
head -n 1 "$file"
while IFS='|' read -r id dummy; do
printf '%s|%s\n' "$id" "$(base64 -w 0 <<<"$dummy")"
done < <(tail -n +2 "$file")
这是由 awk -v n=100 'NR==1{print; next} {for (i=1;i<=n;i++) print}' dummy2.txt > file100
$ ./tst.sh file100
Awk:
real 0m23.247s
user 0m3.755s
sys 0m10.966s
Shell:
real 0m14.512s
user 0m1.530s
sys 0m4.776s
以上时间是由运行这个命令产生的(答案中发布的两个awk脚本的时间大致相同,所以我只是随机选择了一个):
#!/usr/bin/env bash
doawk() {
local file=""
gawk -v q="'" 'BEGIN {
FS=OFS="|"
}
NR==1{
print;
next
}
{
cmd1="echo -n " q q" | base64 -w 0";
print ((cmd1 | getline d1)>0)? OFS d1 : [=14=];
close(cmd1);
}
' "$file"
}
doshell() {
local file=""
head -n 1 "$file"
while IFS='|' read -r id dummy; do
printf '%s|%s\n' "$id" "$(base64 -w 0 <<<"$dummy")"
done < <(tail -n +2 "$file")
}
# Use 3rd-run timing to eliminate cache-ing as a factor
doawk "" >/dev/null
doawk "" >/dev/null
echo "Awk:"
time doawk "" >/dev/null
echo ""
doshell "" >/dev/null
doshell "" >/dev/null
echo "Shell:"
time doshell "" >/dev/null