【问题标题】:Extract positional path argument from list of arguments to "ls" in Bash从参数列表中提取位置路径参数到 Bash 中的“ls”
【发布时间】:2018-02-04 12:57:48
【问题描述】:

我正在尝试解析应传递给 Linux ls 二进制文件的命令行参数列表(包含在特殊的 "$@" Bash 变量中)。

参数可以可选地包含关键字参数,如-h--color--hide 'pattern',并且它们可以可选地包含目录或文件路径(绝对/home、相对./bin 或隐式相对Documents)任何位置。

有没有办法从列表中只提取位置路径参数(如果包含)?

如果不能合理地排除所有边缘情况,我们至少可以实现目标并在路径参数作为最后一个参数给出时提取它吗?

如果它有助于上下文,我将在下一步中使用awk 进一步处理路径参数,通过在每一行附加更多信息(与"show git branch in ls -l" on Ask Ubuntu 相关)来修改ls -alF 的输出.在这里,我遇到的问题是,如果我运行例如ls -alF /home,我在输出中有关于 ./../ 的条目,然后 awk 将处理为当前工作目录的相对路径,而不是指定的 /home


可以在上面关于 Ask Ubuntu 的链接答案中找到实际脚本(Bash 函数)。这是一个最小版本,它跳过调用外部git 命令并解析其输出:

lg (){ 
    ls -alF "$@" | 
    awk '{
        # Split into columns 1-8 and 9+ (file name):
        match($0, /^(\S+\s+){8}(.+)$/, f);
        # do something with the file name using an external command
        # result is stored in b, e.g. "(master)" or an empty string
        b=f[2];
        print $0, b
    }'
; }

示例输出(包含外部调用的原始函数):

$ lg
total 48 
drwxrwxr-x 12 bytecommander bytecommander 4096 Aug 26 14:48 ./ 
drwxr-xr-x 74 bytecommander bytecommander 4096 Aug 26 15:30 ../ 
drwxrwxr-x  6 bytecommander bytecommander 4096 Aug 26 14:43 git1/ (master)
drwxrwxr-x  7 bytecommander bytecommander 4096 Aug 26 14:42 git2/ (develop)
drwxrwxr-x  4 bytecommander bytecommander 4096 Aug 26 14:45 no-git/ 
-rw-rw-r--  1 bytecommander bytecommander    0 Aug 26 14:42 regular-file 

现在,如果我当前的工作目录是例如git1 从上面(这是一个存储库),我像lg /home 一样运行它,ls 的输出中的./ 条目将正确对应于/home,但是我添加的存储库信息不正确当前工作目录,即git1。父目录条目../也一样

【问题讨论】:

  • 你到底想做什么?开始使用 ls 的输出是个坏主意。
  • @chepner 我认为我的最终目标在最后一段中得到了很好的描述。我想要实现的是按原样获取ls -alF 的输出,并通过将一些 git 元信息附加到输出中列出的所有目录来扩展它。我有一个可行的解决方案(请参阅链接),它目前的问题是./.. 条目相对于工作目录而不是可选指定的位置参数来处理。是的,我知道解析ls 不是最好的办法,但替代方法是重写ls,我更不想这样做。
  • 您是否正在尝试编写一个名为myscript -alF /home 并在内部调用ls "$@" 的脚本,然后您还想在脚本调用awk '...' /home 中进行调用?如果是这样,那么 awk 调用将只是 bash 中的 awk '...' "${!#}" - 这就是你想要的吗?如果不是,请使用具体示例脚本和示例输入预期输出来澄清您的问题,即minimal reproducible example
  • @EdMorton 我从包含代码的链接的 Ask Ubuntu 答案中复制了这些内容。这是否符合您的要求,还是您需要其他任何说明?
  • @EdMorton 哦,现在我明白了。感谢您的提示。

标签: bash shell awk command-line-arguments


【解决方案1】:

到目前为止,我最好的猜测是你正在编写一个脚本“myscript”,你想调用它:

myscript -<ls-args> <path>

在 myscript 里面做:

ls "$@"
awk 'stuff' "${!#}"

如果这不是您要查找的内容,请编辑您的问题以澄清。

【讨论】:

  • "${!#}" 在这里做什么?
  • $# 是传递给myscript 的参数数量,所以${!#} 是传递给myscript 的最后一个参数的值。
【解决方案2】:

如果你对 perl 没问题,那么我建议使用 Getopt::Long 包来解析参数。这是一个示例:

#!/usr/bin/perl
use Getopt::Long;

my @args = @ARGV;

GetOptions(
  'a'            => \$opt{'a'},
  'all'          => \$opt{'all'},
  'A'            => \$opt{'A'},
  'almost-all'   => \$opt{'almost-all'},
  'author'       => \$opt{'author'},
  'b'            => \$opt{'b'},
  'escape'       => \$opt{'escape'},
  'block-size=s' => \$opt{'block-size'},
  # ...
  'version'      => \$opt{'version'}
)
or die "Invalid options: @args\n";

my @fileargs = @ARGV;
print "ls args: @args\n";
print "file args: @fileargs\n";

例如perl script.pl -a --author file1 file2 将打印ls args: -a --author file1 file2 file args: file1 file2。您可以添加更多代码来处理文件参数。

至于相对路径名问题:我建议运行find -maxdepth 1 fileordir 而不是ls fileordir 来获取绝对路径。

【讨论】:

  • 我是否可以只获取位置路径参数而忽略其他任何内容,而不先在某处配置所有可能的参数?
  • 好吧,你可以把所有以- 开头的东西都扔掉,因为 ls 只知道-(\w|-\w+(=\w+)?) 形式的参数,但这不会有点小技巧吗?
猜你喜欢
  • 2020-12-13
  • 1970-01-01
  • 1970-01-01
  • 2014-03-26
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多