作为练习,我需要创建一个脚本,它接受2个参数作为输入,
<n>
一个整数值<path>
指向目录 的路径
我需要在路径中创建尽可能多的目录至少有运行<n>
进程的用户。这些文件具有<pid>.txt
格式,并且必须包含ppid时间,和命令
#! /bin/bash
if [ $# -lt 2 ]
then
echo "Hai inserito $#/2 parametri"
echo "<n><path>"
exit 1
fi
if [ "$1" -lt 0 ]
then
echo "errore: Il valore inserito non può essere negativo"
exit 1
fi
if ! [ -d "$2" ]
then
echo "errore: Il path indicato non è una directory"
exit 1
fi
OCCURRENCE=$1
PAT=$2
users=($(ps -Af | awk '{print $1}' | sort | uniq ))
for user in "${users[@]}"
do
processes=$(ps -Af | awk -v user="$user" '$1==user'|wc -l)
if [ "$processes" -gt "$OCCURRENCE" ]
then
mkdir $PAT/$user
ps -Af | awk -v user="$user" -v path="$PAT/$user" '$1=="user" {print $2,$7,$8 >>"$path/"$1".txt" }'
fi
done
问题是没有创建包含各自目录内内容的文件,而程序只正确创建拥有超过<n>
进程的用户的目录。
awk命令有错误吗?有更好的方法来完成这个任务吗?
您的第一个awk
过滤器是正确的:$1==user
。但第二个是错误的:$1=="user"
将第一个字段与字面值字符串user
进行比较,而不是与变量user
的值进行比较。正如在评论中所指出的,你对"$path"
有类似的问题,应该是path
(没有$
,没有引号)。
还请注意,您应该过滤掉ps
输出的第一行,并且,与bash重定向不同,>
是连接的,不需要>>
。
当你使用awk
时,这里有另一个完全基于awk
的解决方案(用GNUawk
测试):
$ ps -Af | awk -v n="$1" -v p="$2" 'NR>1 {
num[$1] += 1
proc[$1][$2 " " $7 " " $8]
}
END {
for(u in num) {
if(num[u] >= n) {
d = p "/" u
system("mkdir -p " d)
for(e in proc[u])
print e > d "/" u ".txt"
}
}
}'
下面的Shellcheck-clean Bash代码演示了执行任务的另一种方法:
#! /bin/bash -p
if (( $# < 2 )); then
echo "Hai inserito $#/2 parametri" >&2
echo "<n><path>" >&2
exit 1
fi
min_proc_count=$1
output_dir=$2
if [[ -z $min_proc_count || $min_proc_count == *[^[:digit:]]* ]]; then
echo 'errore: il valore inserito deve essere un numero positivo' >&2
exit 1
fi
if [[ ! -d $output_dir ]]; then
echo 'errore: Il path indicato non è una directory' >&2
exit 1
fi
ps_output=$(ps -Af --no-headers)
# Get counts of processes for each user
declare -A user_proc_count
while read -r user _; do
user_proc_count[$user]=$(( ${user_proc_count[$user]-0}+1 ))
done <<<"$ps_output"
# Generate per-process output files for users with enough processes
while read -r user pid ppid _ _ _ time cmd; do
(( ${user_proc_count[$user]} < min_proc_count )) && continue
dir=$output_dir/$user
[[ -d $dir ]] || mkdir -v -- "$dir"
printf '%d,%s,%sn' "$ppid" "$time" "$cmd" >"$dir/${pid}.txt"
done <<<"$ps_output"
- 请参阅正确的Bash和shell脚本变量大写,以解释为什么我使用小写变量名而不是像
PAT
和OCCURRENCE
这样的ALL_UPPERCASE名称。 - 看到公认的,优秀的,为什么printf比echo好?来解释为什么我使用
printf
而不是echo
来输出数据。
这是一个基于awk
的解决方案,它不需要任何额外的shell级处理,并直接生成必要的输出。
基于我对ps的业余理解,我认为ps -Ao 'uid pid time command'
可能更符合他/她的目的。
由于我真正不知道的原因,我只能让它在gawk
或mawk2
上工作,而不是mawk-1
或nawk
。
ps -Ao 'uid pid time command' |
gawk -be '
{
528 ___[_=$!-__]
528 sub(_ "[ t]+","")
528 sub("$",($-__)__,___[_])
} END {
1 sub("^[~][/]",ENVIRON["HOME"]"/",____)
gsub("[/]+", "/",____)
sub("[/]$", "",____)
gsub(/47/,"&\&&",____)
1 system(" mkdir -p 47" (____) "47 2>/dev/null")
35 for (_ in ___) {
35 if (+_____ < (gsub(__, "&", ___[_]))) {
5 printf("%s", ___[_]) > (____ "/" _".txt")
}
}
}' _____='THRESHOLD_NUMBER' ____="${DESTINATION_PATH}" __='n'
"$ {DESTINATION_PATH}";后来
total 800
-rw-r--r-- 1 501 staff 11709 May 30 11:13 0.txt
-rw-r--r-- 1 501 staff 509 May 30 11:13 205.txt
-rw-r--r-- 1 501 staff 655 May 30 11:13 262.txt
-rw-r--r-- 1 501 staff 1575 May 30 11:13 278.txt
-rw-r--r-- 1 501 staff 791516 May 30 11:13 501.txt
296 lines 791,175 utf8 (175 uc) 0.755 MB ( 791515) 501.txt
158 lines 11,708 utf8 (0. uc) 0.011 MB ( 11708) 0.txt
6 lines 508 utf8 (0. uc) 0.000 MB ( 508) 205.txt
12 lines 1,574 utf8 (0. uc) 0.002 MB ( 1574) 278.txt
7 lines 654 utf8 (0. uc) 0.001 MB ( 654) 262.txt
==> 0.txt <==
1 4:36.92 /sbin/launchd
105 1:00.85 /usr/libexec/logd
==> 205.txt <==
148 0:32.10 /usr/libexec/locationd
286 0:00.56 /System/Library/PrivateFrameworks/GeoServices.framewor
==> 262.txt <==
346 0:00.84 /usr/sbin/distnoted agent
365 0:00.06 /System/Library/Frameworks/CoreMediaIO.framework/Versi
==> 278.txt <==
113 0:00.46 /System/Library/PrivateFrameworks/MobileAccessoryUpdat
376 0:00.83 /usr/sbin/distnoted agent
==> 501.txt <==
184 0:01.64 /System/Library/CoreServices/loginwindow.app/Contents/
426 0:22.44 /usr/sbin/distnoted agent