传递多个参数到UNIX shell脚本 [英] Passing multiple arguments to a UNIX shell script

查看:155
本文介绍了传递多个参数到UNIX shell脚本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下(bash)的shell脚本,我会用最好的名字杀死多个进程。

I have the following (bash) shell script, that I would ideally use to kill multiple processes by name.

#!/bin/bash
kill `ps -A | grep $* | awk '{ print $1 }'`

不过,虽然该脚本的工作原理是传递一个参数:

However, while this script works is one argument is passed:

末铬

(脚本的名称为结束)

如果多于一个参数传递它不工作:

it does not work if more than one argument is passed:

$结束铬火狐

的grep:火狐:没有这样的文件或目录

grep: firefox: No such file or directory

这是怎么回事呢?

我想到了 $ * 传递多个参数在序列中的shell脚本。我没有打错在我输入任何东西 - 和程序我想杀死(Chrome和Firefox)打开

I thought the $* passes multiple arguments to the shell script in sequence. I'm not mistyping anything in my input - and the programs I want to kill (chrome and firefox) are open.

任何帮助是AP preciated。

Any help is appreciated.

推荐答案

记住的grep 不使用多个参数 - 首先是要搜索的单词,其余是扫描的文件

Remember what grep does with multiple arguments - the first is the word to search for, and the remainder are the files to scan.

还记得 $ * $ * $ @ 所有失去跟踪的参数空白,而神奇的$ @符号没有。

Also remember that $*, "$*", and $@ all lose track of white space in arguments, whereas the magical "$@" notation does not.

所以,对付你的情况,你将需要修改调用的grep 的方式。你要么需要使用的grep -F (又名 fgrep一样)为每个参数选项,或者你需要使用的grep -E (又名 egrep的)与交替。在某种程度上,它取决于你是否会要处理论点,本身包含管道符号。

So, to deal with your case, you're going to need to modify the way you invoke grep. You either need to use grep -F (aka fgrep) with options for each argument, or you need to use grep -E (aka egrep) with alternation. In part, it depends on whether you might have to deal with arguments that themselves contain pipe symbols.

这是令人惊讶的棘手与的grep 一次调用可靠地做到这一点;你很可能是最好关闭容忍运行的管道多次的开销:

It is surprisingly tricky to do this reliably with a single invocation of grep; you might well be best off tolerating the overhead of running the pipeline multiple times:

for process in "$@"
do
    kill $(ps -A | grep -w "$process" | awk '{print $1}')
done

如果运行的开销 PS 一样,多次太痛苦了(它伤害了我写的 - 但我还没有测量的成本),那么你可能做这样的事情:

If the overhead of running ps multiple times like that is too painful (it hurts me to write it - but I've not measured the cost), then you probably do something like:

case $# in
(0) echo "Usage: $(basename $0 .sh) procname [...]" >&2; exit 1;;
(1) kill $(ps -A | grep -w "$1" | awk '{print $1}');;
(*) tmp=${TMPDIR:-/tmp}/end.$$
    trap "rm -f $tmp.?; exit 1" 0 1 2 3 13 15
    ps -A > $tmp.1
    for process in "$@"
    do
         grep "$process" $tmp.1
    done |
    awk '{print $1}' |
    sort -u |
    xargs kill
    rm -f $tmp.1
    trap 0
    ;;
esac

采用纯的xargs 是可以的,因为它在处理过程ID列表和进程ID不包含空格或换行符。这使简单的code的简单情况;复杂的情况下,使用临时文件来保存的 PS 的输出,然后在命令行中每个进程名称,便对其进行扫描。在排序-u 确保如果某个进程发生在所有关键字匹配(例如,的grep -E(火狐|镀铬)将同时匹配),只有一个发送信号。

The use of plain xargs is OK because it is dealing with a list of process IDs, and process IDs do not contain spaces or newlines. This keeps the simple code for the simple case; the complex case uses a temporary file to hold the output of ps and then scans it once per process name in the command line. The sort -u ensures that if some process happens to match all your keywords (for example, grep -E '(firefox|chrome)' would match both), only one signal is sent.

陷阱线等确保临时文件清理,除非有人过于残酷的命令(捕获的信号HUP,INT,QUIT,PIPE和期限,又名1,2,3,13和15;在零捕获退出以任何理由壳)。任何一个脚本创建的临时文件时,你应该有周围使用的文件类似俘获,使得如果处理终止将被清理。

The trap lines etc ensure that the temporary file is cleaned up unless someone is excessively brutal to the command (the signals caught are HUP, INT, QUIT, PIPE and TERM, aka 1, 2, 3, 13 and 15; the zero catches the shell exiting for any reason). Any time a script creates a temporary file, you should have similar trapping around the use of the file so that it will be cleaned up if the process is terminated.

如果你感到谨慎,你有GNU grep的,您可以添加 -w 选项,这样提供的命令行上的名字只匹配整个单词。

If you're feeling cautious and you have GNU Grep, you might add the -w option so that the names provided on the command line only match whole words.

以上所有将与伯恩/科恩/ POSIX /猛砸家庭几乎所有的壳工作(你需要使用反引号与在 $(...)的严格Bourne shell的,而在情况的条件下,领导括号,也不能与Bourne shell的允许)。但是,您可以使用数组来把事情处理的权利。

All the above will work with almost any shell in the Bourne/Korn/POSIX/Bash family (you'd need to use backticks with strict Bourne shell in place of $(...), and the leading parenthesis on the conditions in the case are also not allowed with Bourne shell). However, you can use an array to get things handled right.

n=0
unset args  # Force args to be an empty array (it could be an env var on entry)
for i in "$@"
do
    args[$((n++))]="-e"
    args[$((n++))]="$i"
done
kill $(ps -A | fgrep "${args[@]}" | awk '{print $1}')

本仔细美元的论据p $ pserves间距,并使用完全匹配的进程名称。它避免了临时文件。显示不验证零参数的code;这将必须事先进行。或者你可以添加一行 ARGS [0] ='/肚子疼/ 或类似提供一个默认的东西 - 不存在 - 命令来搜索

This carefully preserves spacing in the arguments and uses exact matches for the process names. It avoids temporary files. The code shown doesn't validate for zero arguments; that would have to be done beforehand. Or you could add a line args[0]='/collywobbles/' or something similar to provide a default - non-existent - command to search for.

这篇关于传递多个参数到UNIX shell脚本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆