假设您的历史文件中有一个类似于下面的shell历史记录:
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。
更新:
输入和输出示例:
$ exctractCommands "find . -type f | x grep 'linux' | wc -l; where ls"
/usr/bin/find
/usr/bin/xargs
/usr/bin/wc
where请你帮我写这个函数好吗?
发布于 2014-01-17 03:39:47
与您希望输出的样子有点混淆,但是应该很容易从下面的脚本中更改(如果您只想要命令路径/别名,只需将out="$i"更改为out="")。注意,bash不擅长处理shell脚本中的别名,因此您必须将它们保存在任何文件中。
#!/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"示例输出
$ ./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空格修正的示例输出
$ 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,并且重复了第一个参数。
$ 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发布于 2014-01-16 23:45:59
您可以尝试首先识别命令中的可执行文件。您可以通过找出$PATH变量中存在哪些标记来完成这个任务。(它们必须在那里,因为否则无法运行命令)注意,当命令中有参数时,这个部分会变得很棘手,这些参数本身就是路径中可执行文件的有效名称。
之后,您可以对每个可执行文件运行“其中”。它本身就是一个unix工具。请看“男人”来解释。
为了识别别名,您也可以简单地使用它,因为“哪个别名”将不会返回任何内容。
发布于 2014-01-17 01:04:49
轻率的回答
# 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
donefind is /usr/bin/find
xargs is /usr/bin/xargs
wc is /usr/bin/wchttps://stackoverflow.com/questions/21175233
复制相似问题