執行AWK in UNIX

2009-07-04 12:34 am
請教一下各位電腦高手

以下是我在linux下執行的dd_kill.dat的內容:

*********************我是分隔線************************
#!/usr/bin/awk -f
BEGIN {
system ("ps -aux | grep ${USER} | grep dd > ${HOME}/dd_kill.log")

Log_file = ENVIRON["HOME"]"/dd_kill.log"
print Log_file
while ( getline < Log_file > 0 ) {
if($ll ~ dd) {
print "kill -9 "$2 " " $ll
system("kill -9 " $2)
}

}
system("rm ${HOME}/dd_kill.log")
}
*********************我是分隔線************************

目的是要kill掉名稱裡包含有"dd"的所有程序

但是當我在UNIX系統下執行時

我有稍作修改(aux->ef):

*********************我是分隔線************************
#!/usr/bin/awk -f
BEGIN {
system ("ps -ef | grep ${USER} | grep dd > ${HOME}/dd_kill.log")

Log_file = ENVIRON["HOME"]"/dd_kill.log"
print Log_file
while ( getline < Log_file > 0 ) {
if($ll ~ dd) {
print "kill -9 "$2 " " $ll
system("kill -9 " $2)
}

}
system("rm ${HOME}/dd_kill.log")
}
*********************我是分隔線************************

結果執行 ./dd_kill.dat的結果如下:

awk: syntax error near line 8
awk: illegal statement near line 8
awk: syntax error near line 9
awk: illegal statement near line 9
awk: syntax error near line 15
awk: illegal statement near line 15

感覺像是UNIX的語法不支援

請問一下要怎麼修改我的程式呢?
更新1:

Dear 可魯: 我在while那一行就出錯了耶 而且我把if($ll ~ dd) 改成if($ll ~ "dd") 這一行的錯誤也還是依然存在耶

回答 (3)

2009-07-08 10:13 pm
✔ 最佳答案
有些觀念須先釐清:
(1).並非所有版本的 awk 皆支援 system() 函數、ENVIRON[] 陣列。linux 的 awk “應” 是 link 到 gawk,故可使用 system、ENVIRON;而您 UNIX 的 awk “應” 是原版、最陽春的 awk。
(2).並非所有 Shell 皆支援 ${USER} 環境變數;即使是相同的 Shell (如 bash),在 linux 中可用 ${USER} 不代表在 UNIX 中也可用 ${USER}。
(3).system() 所叫用的 Shell 因系統而異。

解決 (1) 的問題:改用支援 system()、ENVIRON[] 的 awk (支援 POSIX.1、POSIX.2),如 nawk、gawk。
(2) 與 (3) 的組合會可能造成另一個問題:
假設您所使用的 Shell 為 bash (有定義 ${USER}),而 awk 使用 system() 函式時所叫用的 Shell 為 sh (未定義 ${USER}),則 sh 執行 “ps -ef | grep ${USER} ......” 時,不會認得 ${USER} 是啥,可能造成執行結果有誤。處理這個問題,您可在 awk 程式中自行取得 USER 再代入 system() 的 grep。
另外:
1.“$ll” 似乎不應出現。
2.“ps -ef | grep ${USER} | grep dd” 較嚴謹的做法是 “ps -ef | grep ${USER} | grep dd | grep -v grep”,因 grep 本身有時會出現在 ps -ef 列出的 Process 中,須將 grep 本身剔除。

套用您目前的 awk 程式,加上以上描述的小修改:

#!/usr/bin/nawk -f
BEGIN {
sCommand = "id";
while (sCommand | getline sOutput)
{
split(sOutput, s, /\(|\)/);
USER = s[2];
}
close(sCommand);

system ("ps -fu " USER "| grep dd | grep -v grep > ${HOME}/dd_kill.log")

Log_file = ENVIRON["HOME"]"/dd_kill.log"
print Log_file
while ( getline < Log_file) {
if($0 ~ /dd/) {
print "kill -9 "$2 " " $0
system("kill -9 " $2)
}
system("rm ${HOME}/dd_kill.log")

# 在使用完後,養成 close 的習慣
close(Log_file);
}

您可參考以上 “while (sCommand | getline sOutput)” 的方式修改 “......> ${HOME}/dd_kill.log”,如此可不用產生暫存檔。
除非您想練功,否則不建議使用這種方式達到功能,如可魯兄或 bean_bottom_2 兄所說,可以用簡單的 Shell Script 完成:
kill `ps -fu ${USER}|nawk '$0 ~ /dd/ && $2 ~ /[0-9]+/ { print $2; }'`
若您的 Shell 未定義 ${USER},則可試試 ${LOGNAME}。

可魯兄所提及『因為是該user 的 dd, 因此, 不要用 ps -ef, 而是 ps 即可』,單單用 ps,不代參數,的確『可以過濾掉 USER』,但僅只會得到相同的 Controlling Terminal 下的 Processes,無法取得其外的 Processes;『要kill掉名稱裡包含有"dd"的所有程序』可能會有所遺漏。
2009-07-06 5:10 pm
這一行
if($ll ~ dd) {

改一下
if($ll ~ "dd") {


if( index($ll, "dd") >0 ) {

其實, 這個需求, 不一定要這樣寫. 可以有更簡單的作法.
1. 因為是該user 的 dd, 因此, 不要用 ps -ef, 而是 ps 即可, 這樣竟可以過濾掉 USER
2. ps | awk ' /dd/ { print "kill -9", $1 }'
若正確後
ps | awk ' /dd/ { print "kill -9", $1 | "sh" }'
PS: 請注意您的 Unix ps 出現的第一欄位是否為 PID

2009-07-06 19:46:49 補充:
試看看
while ( (getline < Log_file) > 0 ) {
2009-07-05 8:12 pm
Just out of curiosity, why does it have to be an awk script? It seems a simple shell script can do it better.


收錄日期: 2021-04-30 13:37:49
原文連結 [永久失效]:
https://hk.answers.yahoo.com/question/index?qid=20090703000010KK06936

檢視 Wayback Machine 備份