首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在文本中找到已使用的命令和别名?

问如何在文本中找到已使用的命令和别名?
EN

Stack Overflow用户
提问于 2014-01-16 23:42:45
回答 3查看 223关注 0票数 2

假设您的历史文件中有一个类似于下面的shell历史记录:

代码语言:javascript
复制
find . -type f | x grep 'linux' | wc -l

注意:x是xargs命令的别名。

我想要编写一个shell函数,该函数以上面的文本作为参数,并返回使用过的命令的完整路径。

此文本的返回值应该是一个命令路径数组:("/usr/bin/find" "/usr/bin/xargs" "/usr/bin/wc")

如果我将"whereis where"作为函数的参数,where是一个内置的shell,因此没有它的路径。函数应该返回类似于("/usr/bin/where", "where")的函数。

我想我可以通过将常规的注释应用到文本中来实现这一点,但我知道的正则表达式较少,而且不太熟悉awk。

更新:

输入和输出示例:

代码语言:javascript
复制
$ exctractCommands "find . -type f | x grep 'linux' | wc -l; where ls"
/usr/bin/find 
/usr/bin/xargs
/usr/bin/wc
where

请你帮我写这个函数好吗?

EN

回答 3

Stack Overflow用户

发布于 2014-01-17 03:39:47

与您希望输出的样子有点混淆,但是应该很容易从下面的脚本中更改(如果您只想要命令路径/别名,只需将out="$i"更改为out="")。注意,bash不擅长处理shell脚本中的别名,因此您必须将它们保存在任何文件中。

代码语言:javascript
复制
#!/bin/bash

ali() {
  arg="$*"
  input=$(echo "$arg"| tr ' ' '\n')
  save=""
  while read i; do
    out=$(type "$i" 2>/dev/null)
    if [[ $out == *"aliased to"* ]]; then
      out=${out%%\'*}
      out=${out##*\`}
      out=$(ali "$out")
    elif [[ $out == *"$i is"* && $out != *"builtin"* && $out != *"keyword"* ]]; then
      out=${out##*"$i is"}
    else
      out="$i"
    fi
    save="$save $out"
  done <<< "$input"
  echo "$save"  
}

shopt -s expand_aliases
source ~/.bashrc

ali "$1"

示例输出

代码语言:javascript
复制
$ ./script "find . -type f | x grep 'linux' | wc -l"
 /usr/bin/find . -type f | /usr/bin/xargs  /bin/grep 'linux' |  /usr/bin/wc -l
$ ./script "[[ -f test.txt ]] && ls"
[[ -f test.txt ]] &&  /bin/ls 
$ ./script ":> test.txt"
:> test.txt
$ ./script "ll"
/bin/ls -lhtr 

有些带有间隔/转义的bug应该很容易用sed修复,或者只需要echo -e $(./script "whatever")就可以在这里工作。

使用out="“而不是out="$i”和hackish空格修正的示例输出

代码语言:javascript
复制
$ echo -e $(./script "find . -type f | x grep 'linux' | wc -l")
/usr/bin/find /usr/bin/xargs /bin/grep /usr/bin/wc
$ echo -e $(./script "[[ -f test.txt ]] && ls")
/bin/ls 
$ echo -e $(./script ":> test.txt")

$ echo -e $(./script "ll")
/bin/ls 

您想要的更新精确输出应该不会太难在脚本中更改。但更简单的是,将out="$i"更改为out=""并执行(或制作一个包装器来完成)。还请注意,我在上面的脚本中添加了save="",因为在某个地方保存了$save,并且重复了第一个参数。

代码语言:javascript
复制
$ echo -e $(./script "find . -type f | x grep 'linux' | wc -l") | tr ' ' '\n'
/usr/bin/find
/usr/bin/xargs
/bin/grep
/usr/bin/wc

$ echo -e $(./test.sh "find . -type f | x grep 'linux' | wc -l; where ls") | tr ' ' '\n'
/usr/bin/find
/usr/bin/xargs
/bin/grep
/usr/bin/wc
/bin/ls
票数 1
EN

Stack Overflow用户

发布于 2014-01-16 23:45:59

您可以尝试首先识别命令中的可执行文件。您可以通过找出$PATH变量中存在哪些标记来完成这个任务。(它们必须在那里,因为否则无法运行命令)注意,当命令中有参数时,这个部分会变得很棘手,这些参数本身就是路径中可执行文件的有效名称。

之后,您可以对每个可执行文件运行“其中”。它本身就是一个unix工具。请看“男人”来解释。

为了识别别名,您也可以简单地使用它,因为“哪个别名”将不会返回任何内容。

票数 0
EN

Stack Overflow用户

发布于 2014-01-17 01:04:49

轻率的回答

代码语言:javascript
复制
# split the pipeline. 
# note this is insufficient: also need to split on ; && ||
# and be aware that the first char in the command might be ( or {
IFS='|' read -ra cmds << 'END'
find . -type f | x grep 'linux' | wc -l
END


for cmd in "${cmds[@]}"; do 
    set -- $cmd
    case $(type -t $1) in
        file) type $1 ;;
        alias) [[ $(alias $1) =~ =\'([^\'[:blank:]]+) ]] && 
               type ${BASH_REMATCH[1]}
               ;; 
    esac
done
代码语言:javascript
复制
find is /usr/bin/find
xargs is /usr/bin/xargs
wc is /usr/bin/wc
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21175233

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档