在 bash 中处理来自 file/cli/stdin 的参数

发布于 2024-11-28 03:47:48 字数 1022 浏览 2 评论 0原文

我可以看到自己最终编写了很多脚本,这些脚本根据命令行上的一些参数执行某些操作。

然后,这将发展到使用调度程序多次自动执行或多或少相同的事情。

为了防止自己必须为参数的每个变体创建一个新作业,我想创建一个简单的脚本框架,我可以使用它来快速创建采用相同参数的脚本:

  • 命令行
  • 来自指定路径的文件命令行
  • 从 stdin 到 eof

我从 TAB delim 文件中获取参数或配置的最初方法如下:

if [ -f "$1" ]; then
    echo "Using config file '$1'"
    IFS='   '
    cat $1 | grep -v "^#" | while read line; do
            if [ "$line" != "" ]; then
                    echo $line
                    #call fn with line as args
            fi
    done
    unset IFS
elif [ -d "$1" ]; then
    echo "Using cli arguments..."
    #call fn with $1 $2 $3 etc...
else
    echo "Read from stdin, ^d will terminate"
    IFS='   '
    while read line; do
            if [ "$(echo $line | grep -v "^#")" != "" ]; then
                    #call fn with line as args
            fi
    done
    unset IFS
fi

因此,对于所有以前无疑做过此类事情的人:

  1. 您会/会如何去做呢?
  2. 我是不是太程序化了——用 awk 或类似的东西可以更好地完成这个任务吗?
  3. 无论如何,这是最好的方法吗?

I can see myself ending up writing a lot of scripts which do some thing based on some arguments on the command line.

This then progresses to doing more or less the same thing multiple times automated with a scheduler.

To prevent myself having to create a new job for each variation on the arguments, I would like to create a simple script skeleton which I can use to quickly create scripts which take the same arguments from:

  • The command line
  • A file from a path specified on the command line
  • From stdin until eof

My initial approach for taking arguments or config from a TAB delim file was as follows:

if [ -f "$1" ]; then
    echo "Using config file '$1'"
    IFS='   '
    cat $1 | grep -v "^#" | while read line; do
            if [ "$line" != "" ]; then
                    echo $line
                    #call fn with line as args
            fi
    done
    unset IFS
elif [ -d "$1" ]; then
    echo "Using cli arguments..."
    #call fn with $1 $2 $3 etc...
else
    echo "Read from stdin, ^d will terminate"
    IFS='   '
    while read line; do
            if [ "$(echo $line | grep -v "^#")" != "" ]; then
                    #call fn with line as args
            fi
    done
    unset IFS
fi

So to all those who have doubtless done this kind of thing before:

  1. How did/would you go about it?
  2. Am I being too procedural - could this be better done with awk or similar?
  3. Is this the best approach anyway?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

深居我梦 2024-12-05 03:47:48

不确定我是否有点离谱,但听起来您正在尝试重新发明 xargs。

如果您有一个脚本,通常这样调用

$ your_script.sh -d foo bar baz

您可以从标准输入获取参数,如下所示:

$ xargs your_script.sh
-d foo
bar
baz
^D

从文件

$ cat config_file | xargs your_script.sh

(假设 config_file 具有以下内容)

-d foo bar 
baz

或从多个配置文件

$ cat config_file1 config_file2 | xargs your_script.sh

Not sure whether I'm a bit wide of the mark, but it sounds like you are trying to reinvent xargs.

If you have a script, normally invoked as such

$ your_script.sh -d foo bar baz

You can get the parameters from stdin as follows:

$ xargs your_script.sh
-d foo
bar
baz
^D

Our from a file

$ cat config_file | xargs your_script.sh

(assuming that config_file has the following content)

-d foo bar 
baz

Or from multiple config files

$ cat config_file1 config_file2 | xargs your_script.sh
淡莣 2024-12-05 03:47:48

您能想到一个具有您所描述的行为的标准 Unix 实用程序吗? (不,我不能。) 这表明你与你的目标略有偏离。

-f "$1"-d "$1" 的测试并不常规,但如果您的脚本仅适用于目录,也许这是有意义的。

最终,我认为您需要一个如下接口:

your_cmd [-f argumentlist] [file ...]

显式但可选的 -f argumentlist 允许您指定要在命令行上读取的文件。否则,将处理命令行上指定的文件,除非没有此类参数,在这种情况下,将从标准输入读取要处理的文件名。这更接近于传统组织。我们可以稍后讨论如何处理名称中包含空格和换行符的文件名。

您的代码核心将被编写为一次接受/处理一个文件名。这可以写成一个 shell 函数,这样可以最大限度地重用。

while getopts f: opt
do
    case $opt in
    (f) while read file; do shell_function $file; done < $OPTARG; exit 0;;
    (*) : Error handling etc;;
    esac
done
shift $(($OPTIND - 1))
case $# in
(0) while read file; do shell_function $file; done; exit 0;;
(*) for file in "$@"; do shell_function $file; done; exit 0;;
esac

对此进行变体并不难。它也相当紧凑。

Can you think of a standard Unix utility that behaves as you describe? (No, I can't.) That suggests that you are slightly off-target with your goal.

The testing of -f "$1" and -d "$1" is not conventional, but if your script only works on directories, maybe it makes sense.

Ultimately, I think you need an interface like:

your_cmd [-f argumentlist] [file ...]

The explicit but optional -f argumentlist allows you to specify the file to read from on the command line. Otherwise, the files specified on the command line are processed, unless there are no such arguments, in which case the file names to be processed are read from standard input. This is a lot closer to a conventional organization. We can debate about the handling of file names with spaces and newlines in the names some other time.

The core of your code will be written to accept/process one file name at a time. This might be written as a shell function, which allows the maximum reuse.

while getopts f: opt
do
    case $opt in
    (f) while read file; do shell_function $file; done < $OPTARG; exit 0;;
    (*) : Error handling etc;;
    esac
done
shift $(($OPTIND - 1))
case $# in
(0) while read file; do shell_function $file; done; exit 0;;
(*) for file in "$@"; do shell_function $file; done; exit 0;;
esac

It is not very hard to ring the variations on this. It is also tolerably compact.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文