ฉันต้องการคำสั่งเชลล์ / bash ที่เป็นอิสระจากแพลตฟอร์ม (Linux / Unix | OSX) ซึ่งจะพิจารณาว่ามีกระบวนการใดกำลังทำงานอยู่หรือไม่ เช่นmysqld
, httpd
... เป็นวิธีที่คำสั่ง / ง่ายที่สุดในการทำเช่นนี้คืออะไร?
ฉันต้องการคำสั่งเชลล์ / bash ที่เป็นอิสระจากแพลตฟอร์ม (Linux / Unix | OSX) ซึ่งจะพิจารณาว่ามีกระบวนการใดกำลังทำงานอยู่หรือไม่ เช่นmysqld
, httpd
... เป็นวิธีที่คำสั่ง / ง่ายที่สุดในการทำเช่นนี้คืออะไร?
คำตอบ:
ในขณะที่pidof
และpgrep
เป็นเครื่องมือที่ยอดเยี่ยมในการพิจารณาว่าอะไรกำลังทำงานอยู่ แต่น่าเสียดายที่ทั้งคู่ไม่สามารถใช้งานได้ในบางระบบปฏิบัติการ ข้อผิดพลาดที่แน่นอนคือการใช้สิ่งต่อไปนี้:ps cax | grep command
ผลลัพธ์บน Gentoo Linux:
14484? ส 0:00 apache2 14667? ส 0:00 apache2 พ.ศ. 24620? Sl 0:00 apache2 21132? เอส 0:04 apache2
ผลลัพธ์บน OS X:
42582 ?? Z 0: 00.00 น. 46529 ?? Z 0: 00.00 น. 46539 ?? Z 0: 00.00 น. 46547 ?? Z 0: 00.00 น. 46586 ?? Z 0: 00.00 น. 46594 ?? Z 0: 00.00 น.
ทั้งบน Linux และ OS X grep จะส่งคืนรหัสออกเพื่อให้ง่ายต่อการตรวจสอบว่าพบกระบวนการหรือไม่:
#!/bin/bash
ps cax | grep httpd > /dev/null
if [ $? -eq 0 ]; then
echo "Process is running."
else
echo "Process is not running."
fi
นอกจากนี้หากคุณต้องการรายชื่อ PID คุณสามารถ grep ได้อย่างง่ายดายเช่นกัน:
ps cax | grep httpd | grep -o '^ [] * [0-9] *'
เอาต์พุตของใครเหมือนกันบน Linux และ OS X:
3519 3521 3523 3524
ผลลัพธ์ต่อไปนี้เป็นสตริงว่างทำให้แนวทางนี้ปลอดภัยสำหรับกระบวนการที่ไม่ได้ทำงาน:
ก้อง ps cax | grep aasdfasdf | grep -o '^[ ]*[0-9]*'
วิธีนี้เหมาะสำหรับการเขียนการทดสอบสตริงว่างเปล่าอย่างง่ายจากนั้นจึงวนซ้ำผ่าน PID ที่ค้นพบ
#!/bin/bash
PROCESS=$1
PIDS=`ps cax | grep $PROCESS | grep -o '^[ ]*[0-9]*'`
if [ -z "$PIDS" ]; then
echo "Process not running." 1>&2
exit 1
else
for PID in $PIDS; do
echo $PID
done
fi
คุณสามารถทดสอบได้โดยบันทึกลงในไฟล์ (ชื่อ "running") โดยมีสิทธิ์ดำเนินการ (กำลังรัน chmod + x) และดำเนินการด้วยพารามิเตอร์: ./running "httpd"
#!/bin/bash
ps cax | grep httpd
if [ $? -eq 0 ]; then
echo "Process is running."
else
echo "Process is not running."
fi
คำเตือน!!!
โปรดทราบว่าคุณกำลังแยกวิเคราะห์ผลลัพธ์ps ax
ซึ่งหมายความว่าดังที่เห็นในเอาต์พุตของ Linux ไม่เพียงแค่จับคู่กับกระบวนการเท่านั้น แต่ยังรวมถึงอาร์กิวเมนต์ที่ส่งไปยังโปรแกรมนั้นด้วย ฉันขอแนะนำอย่างยิ่งให้ระบุให้เฉพาะเจาะจงมากที่สุดเมื่อใช้วิธีนี้ (เช่น./running "mysql"
จะตรงกับกระบวนการ 'mysqld' ด้วย) ฉันขอแนะนำให้ใช้which
เพื่อตรวจสอบกับเส้นทางแบบเต็มหากเป็นไปได้
อ้างอิง:
grep
นอกจากนี้ยังจะได้พบกับตัวเองทำงาน (เช่นps cax | grep randomname
มักจะกลับ 0 เพราะgrep
พบgrep randomname
(หวังว่านี้เป็นที่ชัดเจน ... ) หนึ่งในการแก้ไขคือการเพิ่มวงเล็บรอบตัวอักษรตัวแรกของชื่อกระบวนการเช่น. ps cax | grep [r]andomname
.
ps cax | rev | cut -f1 -d' ' | rev
จะแสดงเฉพาะคอลัมน์ชื่อเพื่อการแยกวิเคราะห์ที่ง่ายขึ้น
ps cax
อาจไม่แสดงชื่อคำสั่งทั้งหมด เช่นพิมพ์ "โครเมียมเรียกดู" แทน "โครเมียมเบราว์เซอร์"
การค้นหากระบวนการโดยพยายามทำการจดจำรูปแบบบางอย่างบนอาร์กิวเมนต์ของกระบวนการ (เช่นpgrep "mysqld"
) เป็นกลยุทธ์ที่ถึงวาระที่จะล้มเหลวไม่ช้าก็เร็ว จะเกิดอะไรขึ้นถ้าคุณมี mysqld สองตัวทำงานอยู่? ลืมวิธีการนั้น คุณอาจทำให้ถูกต้องชั่วคราวและอาจใช้งานได้ประมาณปีหรือสองปี แต่แล้วมีบางอย่างเกิดขึ้นโดยที่คุณไม่ได้คิด
เฉพาะรหัสกระบวนการ (pid) เท่านั้นที่ไม่ซ้ำกันอย่างแท้จริง
เก็บ pid ไว้เสมอเมื่อคุณเปิดบางสิ่งในพื้นหลัง ใน Bash สามารถทำได้ด้วย$!
ตัวแปร Bash คุณจะช่วยตัวเองได้มากโดยการทำเช่นนั้น
ดังนั้นคำถามจึงกลายเป็นว่าจะรู้ได้อย่างไรว่า pid กำลังทำงานอยู่
เพียงแค่ทำ:
ps -o pid = -p <pid>
นี่คือ POSIX และด้วยเหตุนี้จึงพกพาได้ มันจะคืนค่า pid เองหากกระบวนการทำงานอยู่หรือไม่ส่งคืนอะไรเลยหากกระบวนการไม่ทำงาน การพูดคำสั่งอย่างเคร่งครัดจะส่งคืนคอลัมน์เดียวpid
แต่เนื่องจากเราได้กำหนดให้ส่วนหัวของหัวเรื่องว่าง (สิ่งที่อยู่ข้างหน้าเครื่องหมายเท่ากับทันที) และนี่เป็นคอลัมน์เดียวที่ร้องขอจากนั้นคำสั่ง ps จะไม่ใช้ส่วนหัวเลย ซึ่งเป็นสิ่งที่เราต้องการเพราะทำให้การแยกวิเคราะห์ง่ายขึ้น
สิ่งนี้จะทำงานบน Linux, BSD, Solaris และอื่น ๆ
อีกกลยุทธ์หนึ่งคือการทดสอบค่าออกจากps
คำสั่งด้านบน ควรเป็นศูนย์หากกระบวนการกำลังทำงานและไม่ใช่ศูนย์หากไม่ใช่ ข้อมูลจำเพาะ POSIX ระบุว่าps
ต้องออก> 0 หากมีข้อผิดพลาดเกิดขึ้น แต่ไม่ชัดเจนสำหรับฉันว่าอะไรเป็น 'ข้อผิดพลาด' ดังนั้นฉันจึงไม่ได้ใช้กลยุทธ์นั้นเป็นการส่วนตัวแม้ว่าฉันค่อนข้างมั่นใจว่ามันจะใช้ได้ดีกับแพลตฟอร์ม Unix / Linux
grep <sometext>
เพื่อค้นหากระบวนการที่กำหนดแสดงว่าคุณได้ทำอะไรผิดพลาดเมื่อคุณเริ่มกระบวนการ IMHO ฉันใช้คำถามนี้จากคำถามของ OP ที่ว่าเขาควบคุมวิธีการเริ่มต้นกระบวนการได้จริง
ในการกระจาย Linux ส่วนใหญ่คุณสามารถใช้pidof
(8)
มันจะพิมพ์รหัสกระบวนการของอินสแตนซ์ที่รันอยู่ทั้งหมดของกระบวนการที่ระบุหรือไม่มีอะไรเลยหากไม่มีอินสแตนซ์กำลังทำงานอยู่
ตัวอย่างเช่นในระบบของฉัน (ฉันมีสี่อินสแตนซ์bash
และหนึ่งอินสแตนซ์ของการremmina
ทำงาน):
$ pidof bash remmina
6148 6147 6144 5603 21598
ในหน่วยงานอื่นpgrep
หรือการรวมกันของps
และgrep
จะบรรลุสิ่งเดียวกันดังที่คนอื่น ๆ ได้ชี้ให้เห็นโดยชอบธรรม
pidof httpd
ทำงานได้ดีบน Red Hat 5 แต่ใน Red Hat 4 ของฉันpidof
ไม่มีอยู่ :-(
สิ่งนี้ควรใช้ได้กับ Unix, BSD และ Linux ส่วนใหญ่:
PATH=/usr/ucb:${PATH} ps aux | grep httpd | grep -v grep
ทดสอบเมื่อ:
PATH=...
]ps
ใช่เพียง เพื่อหลีกเลี่ยงข้อที่สองgrep
ฉันขอแนะนำ:ps aux | grep [h]ttpd
grep
ผมไม่ได้ใช้วงเล็บเคล็ดลับตารางที่นี่เพื่อให้ง่ายต่อการใส่ตัวแปรเข้าไปในหลัก
วิธีที่ง่ายที่สุดคือใช้ ps และ grep:
command="httpd"
running=`ps ax | grep -v grep | grep $command | wc -l`
if [ running -gt 0 ]; then
echo "Command is running"
else
echo "Command is not running"
fi
หากคำสั่งของคุณมีอาร์กิวเมนต์คำสั่งคุณสามารถใส่ 'grep cmd_arg1' เพิ่มเติมหลัง 'grep $ command' เพื่อกรองกระบวนการที่เป็นไปได้อื่น ๆ ที่คุณไม่สนใจออกไป
ตัวอย่าง: แสดงให้ฉันเห็นว่ากระบวนการ java ใด ๆ ที่มีอาร์กิวเมนต์ที่ให้มา:
-Djava.util.logging.config.file = logging.properties
กำลังวิ่ง
ps ax | grep -v grep | grep java | grep java.util.logging.config.file=logging.properties | wc -l
ps cax
grep -v
ตัวอย่างเช่นคุณสามารถใช้: ps cax | grep java > /dev/null || echo "Java not running"
.
เพียงเล็กน้อยนอกจากนี้ถ้าคุณเพิ่ม-c
ธง PS, คุณไม่จำเป็นต้องลบบรรทัดที่มีกระบวนการ grep ด้วยgrep -v
หลังจากนั้น ได้แก่
ps acux | grep cron
คือการพิมพ์ทั้งหมดที่คุณต้องการในระบบ bsd-ish (ซึ่งรวมถึง MacOSX) คุณสามารถละทิ้งได้-u
หากต้องการข้อมูลน้อย
ในระบบที่พันธุศาสตร์ของps
คำสั่งเนทีฟชี้กลับไปที่ SysV คุณจะใช้
ps -e |grep cron
หรือ
ps -el |grep cron
สำหรับรายชื่อที่มีมากกว่า pid และชื่อกระบวนการ แน่นอนคุณสามารถเลือกช่องเฉพาะเพื่อพิมพ์โดยใช้-o <field,field,...>
ตัวเลือก
การรวบรวมคำแนะนำต่างๆเข้าด้วยกันเวอร์ชันที่สะอาดที่สุดที่ฉันสามารถหาได้ (โดยไม่มี grep ที่ไม่น่าเชื่อถือซึ่งเรียกส่วนต่างๆของคำ) คือ:
kill -0 $(pidof mysql) 2> /dev/null || echo "Mysql ain't runnin' message/actions"
kill -0 ไม่ได้ฆ่ากระบวนการ แต่ตรวจสอบว่ามีอยู่จริงหรือไม่จากนั้นส่งคืนจริงหากคุณไม่มี pidof ในระบบของคุณให้เก็บ pid เมื่อคุณเปิดกระบวนการ:
$ mysql &
$ echo $! > pid_stored
จากนั้นในสคริปต์:
kill -0 $(cat pid_stored) 2> /dev/null || echo "Mysql ain't runnin' message/actions"
ฉันใช้pgrep -l httpd
แต่ไม่แน่ใจว่ามีอยู่ในแพลตฟอร์มใด ...
ใครสามารถยืนยันบน OSX ได้บ้าง?
pidof
กรุณาตรวจสอบด้วยได้ไหม ตกลงคุณทำ ขอบคุณ. ดังนั้นเราควรหาอย่างอื่นที่ทำงานบน OSX ... พื้นฐานของคุณps|grep
อาจเป็นโซลูชันเดียว ;-)
เมื่อคุณเปิดใช้งาน PID จะถูกบันทึกไว้ใน$!
ตัวแปร บันทึก PID นี้ลงในไฟล์
จากนั้นคุณจะต้องตรวจสอบว่า PID นี้สอดคล้องกับกระบวนการที่กำลังทำงานอยู่หรือไม่ นี่คือสคริปต์โครงกระดูกที่สมบูรณ์:
FILE="/tmp/myapp.pid"
if [ -f $FILE ];
then
PID=$(cat $FILE)
else
PID=1
fi
ps -o pid= -p $PID
if [ $? -eq 0 ]; then
echo "Process already running."
else
echo "Starting process."
run_my_app &
echo $! > $FILE
fi
ขึ้นอยู่กับคำตอบของpeterh
. เคล็ดลับในการทราบว่า PID ที่กำหนดกำลังทำงานอยู่ในps -o pid= -p $PID
คำสั่งหรือไม่
วิธีนี้สามารถใช้ได้ในกรณีที่คำสั่ง 'ps', 'pidof' และส่วนที่เหลือไม่สามารถใช้ได้ โดยส่วนตัวฉันใช้ procfs บ่อยมากในเครื่องมือ / สคริปต์ / โปรแกรมของฉัน
egrep -m1 "mysqld$|httpd$" /proc/[0-9]*/status | cut -d'/' -f3
คำอธิบายเล็กน้อยว่าเกิดอะไรขึ้น:
สิ่งนี้จะพิมพ์จำนวนกระบวนการที่มีชื่อฐานเป็น "โครเมียมเบราว์เซอร์":
ps -e -o args= | awk 'BEGIN{c=0}{
if(!match($1,/^\[.*\]$/)){sub(".*/","",$1)} # Do not strip process names enclosed by square brackets.
if($1==cmd){c++}
}END{print c}' cmd="chromium-browser"
หากสิ่งนี้พิมพ์เป็น "0" แสดงว่ากระบวนการไม่ทำงาน คำสั่งถือว่าพา ธ กระบวนการไม่มีช่องว่าง ฉันไม่ได้ทดสอบสิ่งนี้ด้วยกระบวนการที่ถูกระงับหรือกระบวนการซอมบี้
ทดสอบโดยใช้gwak
เป็นawk
ทางเลือกใน Linux
นี่คือโซลูชันที่หลากหลายมากขึ้นพร้อมตัวอย่างการใช้งาน:
#!/bin/sh
isProcessRunning() {
if [ "${1-}" = "-q" ]; then
local quiet=1;
shift
else
local quiet=0;
fi
ps -e -o pid,args= | awk 'BEGIN{status=1}{
name=$2
if(name !~ /^\[.*\]$/){sub(".*/","",name)} # strip dirname, if process name is not enclosed by square brackets.
if(name==cmd){status=0; if(q){exit}else{print $0}}
}END{exit status}' cmd="$1" q=$quiet
}
process='chromium-browser'
printf "Process \"${process}\" is "
if isProcessRunning -q "$process"
then printf "running.\n"
else printf "not running.\n"; fi
printf "Listing of matching processes (PID and process name with command line arguments):\n"
isProcessRunning "$process"
นี่คือเวอร์ชันของฉัน คุณสมบัติ:
สคริปต์:
#!/bin/bash
# $1 - cmd
# $2 - args
# return: 0 - no error, running; 1 - error, not running
function isRunning() {
for i in $(pidof $1); do
cat /proc/$i/cmdline | tr '\000' ' ' | grep -F -e "$2" 1>&2> /dev/null
if [ $? -eq 0 ]; then
return 0
fi
done
return 1
}
isRunning java "-Djava.util.logging.config.file=logging.properties"
if [ $? -ne 0 ]; then
echo "not running, starting..."
fi
ไม่มีคำตอบใดที่เหมาะกับฉันดังนั้นนี่คือของฉัน:
process="$(pidof YOURPROCESSHERE|tr -d '\n')"
if [[ -z "${process// }" ]]; then
echo "Process is not running."
else
echo "Process is running."
fi
คำอธิบาย:
|tr -d '\n'
วิธีนี้จะลบการส่งคืนแคร่ที่สร้างโดยเทอร์มินัล ส่วนที่เหลือสามารถอธิบายได้ด้วยนี้โพสต์
ฟังก์ชันเชลล์ต่อไปนี้อิงตามคำสั่งและอ็อพชันมาตรฐาน POSIX เท่านั้นควรใช้ได้กับระบบ Unix และ linux ส่วนใหญ่ (ถ้าไม่มี) :
isPidRunning() {
cmd=`
PATH=\`getconf PATH\` export PATH
ps -e -o pid= -o comm= |
awk '$2 ~ "^.*/'"$1"'$" || $2 ~ "^'"$1"'$" {print $1,$2}'
`
[ -n "$cmd" ] &&
printf "%s is running\n%s\n\n" "$1" "$cmd" ||
printf "%s is not running\n\n" $1
[ -n "$cmd" ]
}
$ isPidRunning httpd
httpd is running
586 /usr/apache/bin/httpd
588 /usr/apache/bin/httpd
$ isPidRunning ksh
ksh is running
5230 ksh
$ isPidRunning bash
bash is not running
โปรดทราบว่าจะหายใจไม่ออกเมื่อส่งชื่อคำสั่ง "0]" ที่น่าสงสัยและจะไม่สามารถระบุกระบวนการที่มีช่องว่างฝังอยู่ในชื่อได้
โปรดทราบด้วยว่าโซลูชันที่ได้รับการโหวตและได้รับการยอมรับมากที่สุดต้องการps
ตัวเลือกที่ไม่พกพาและใช้เชลล์โดยไม่จำเป็นแม้ว่าจะได้รับความนิยม แต่ก็ไม่รับประกันว่าจะมีอยู่ในเครื่อง Unix / Linux ทุกเครื่อง ( bash
)
$ isPidRunning 0]
พิมพ์เช่น "0] กำลังทำงาน 3 [ksoftirqd / 0] 8 [rcuop / 0] 17 [rcuos / 0] 26 [rcuob / 0] 34 [migration / 0] 35 [watchdog / 0]" ที่นี่