[英]An alias in .bashrc fails vs command line succeeds
I run this from a user's home dir to show me the most recent files while omitting the shell profile files: 我从用户的主目录运行此文件,以显示最新文件,同时省略了shell配置文件:
find ./ -type f -printf "%T@ %p\n"|grep -vP "/\.(bash|emacs|gtkrc|kde/|zshrc)" |sort -n| tail -10|cut -f2- -d" "|while read EACH; do ls -l "$EACH"; done;
This works, but just not as well when placed in my .bashrc as an alias: 这有效,但是放在我的.bashrc中作为别名时效果不佳:
alias recentfiles='find ./ -type f -printf "%T@ %p\n"|grep -vP "/\.\(bash|emacs|gtkrc|kde/|zshrc\)"|sort -n| tail -10|cut -f2- -d" "|while read EACH; do ls -l "$EACH"; done;'
In the image you see the results without doing any filtering, followed by the desired result using grep -v
for filtering which works on command line. 在图像中,您看到的结果没有进行任何过滤,然后使用
grep -v
进行过滤就可以在命令行上获得所需的结果。 Then final result - only partially succeeds in weeding out those files. 然后是最终结果-仅部分成功清除了这些文件。
I have tried using bash_ and [b]ash. 我试过使用bash_和[b] ash。 Not even bas (which fails to even get .basin) work ?!?
甚至bas(甚至无法获得.basin)都无法工作?!? And also I can use macs or acs AND still get the .emacs omitted so obviously the syntax in my alias is not respecting the /.
而且我也可以使用macs或acs并仍然省略.emacs,因此显然别名中的语法不遵守/。 either.
要么。 Not a problem with reserved words as I originally thought.
就像我最初想的那样,保留字不是问题。
I DO get the expected results if I place my original command as is in a file and then use the alias that way: alias recentfiles='. 怎么做 ,如果我把我原来的命令是在一个文件中,然后使用别名的方式得到预期的结果: 别名recentfiles =”。 /root/mycommands/recentfiles'
/ root / mycommands / recentfiles'
Can someone explain or point me to a reference to understand what is at play here? 有人可以解释或指点我一下以了解此处的作用吗? I wouldn't know what phrase with the proper terms to search on.
我不知道要搜索带有适当术语的短语。
This should fix your problems: 这应该可以解决您的问题:
alias recentfiles='find ./ -type f -printf "%T@ %p\n"|grep -vP "/\.(bash|emacs|gtkrc|kde/|zshrc)"|sort -n| tail -10|cut -f2- -d" "|while read EACH; do ls -l "$EACH"; done;'
The issue is with grep -P
, where -P makes it use the perl regular expressions. 问题在于
grep -P
,其中-P使它使用perl正则表达式。 In perl there is no need to use \\ in grouping. 在perl中,无需在分组中使用\\。 So
(bash|emacs|...)
instead of \\(bash|emacs|...\\)
. 因此
(bash|emacs|...)
代替\\(bash|emacs|...\\)
。 I really doubt it worked outside of .bashrc, unless you have some alias for grep
which make it behave differently outside of .bashrc
. 我真的怀疑它是否可以在.bashrc之外运行,除非您为
grep
设置了别名,从而使它在.bashrc
之外的行为有所不同。
As other have said in the comments, your filtering is inefficient. 正如其他人在评论中所说,您的过滤效率很低。 Better rewrite your command with:
最好用以下命令重写命令:
find ./ \( -name ".bash*" -o -name ".emacs*" -o -name .gtkrc -o -name .kde -o -name .zshrc \) -prune -o \( -type f -printf "%T@ %p\n" \) |sort -n| tail -10|cut -f2- -d" "| tr "\n" "\0" | xargs -0 ls -l;
This way it will not waste time searching files inside .emacs.d/
or inside .kde/
, and will immediately prune the search. 这样,它不会浪费时间在
.emacs.d/
或.kde/
搜索文件,并且会立即修剪搜索。 Also, xargs -0 ls -l
is so much shorter and clearer than the while loop. 同样,
xargs -0 ls -l
比while循环更短,更清晰。
To avoid issues with filenames that contain newlines, better use \\0 characters, that are never part of a file name: 为避免包含换行符的文件名出现问题,请更好地使用\\ 0字符,这些字符绝不属于文件名:
find ./ \( -name ".bash*" -o -name .emacs -o -name .gtkrc -o -name .kde -o -name .zshrc \) -prune -o \( -type f -printf "%T@ %p\0" \) |sort -n -z | tail -z -n -10| cut -z -f2- -d" " | xargs -0 ls -l
Use a function instead. 改用一个函数。
There are several major issues with aliases: 别名有几个主要问题:
Because you pass your content to be string-prefixed inside quotes when creating an alias, it's parsed differently than it would be when typed directly at the command line. 由于在创建别名时将内容传递给使用引号括起来的字符串,因此,其解析方式与直接在命令行中键入时的解析方式不同。
Because an alias is simple prefix substitution, they don't have their own arguments ( $1
, $2
, etc); 因为别名是简单的前缀替换,所以它们没有自己的参数(
$1
, $2
等); they don't have a call stack; 他们没有调用堆栈; debugging mechanisms like
PS4=':$BASH_SOURCE:$LINENO+'; set -x
调试机制,例如
PS4=':$BASH_SOURCE:$LINENO+'; set -x
PS4=':$BASH_SOURCE:$LINENO+'; set -x
can't tell you which file code from an alias originated in; PS4=':$BASH_SOURCE:$LINENO+'; set -x
无法告诉您别名源自哪个文件代码; etc. 等等
Aliases are an interactive feature; 别名是一种交互式功能。 POSIX doesn't mandate that shells support them at all, and they're turned off by default during script execution.
POSIX完全不要求外壳程序支持它们,并且在脚本执行期间默认情况下将其关闭。
Functions solve all these problems. 函数解决了所有这些问题。
recentfiles() {
find ./ \
'(' -name '.bash*' -o -name '.emacs*' -o -name .gtkrc -o -name .kde -o -name .zshrc ')' -prune \
-o -type f -printf "%T@ %p\0" |
sort -nz |
tail -z -n -10 |
while read -d' ' _ && IFS= read -r -d '' file; do
printf '%s\0' "$file"
done |
xargs -0 ls -ld --
}
Note that I also made several other changes: 请注意,我还进行了其他一些更改:
\\n
as a separator, the above code uses \\0
. \\n
作为分隔符,而是使用\\0
。 This is because newlines can be found in filenames; sort
and tail
support newline delimiters, so the -z
options used above are GNUisms). sort
和tail
支持换行符分隔符,因此,上面使用的-z
选项是GNUisms)。 grep -v
to remove dotfiles, I used the -prune
option to find
. grep -v
删除点文件,而是使用-prune
选项来find
。 This is particularly important for directories like .kde
, since it stops find
from spending the time and I/O bandwidth to recurse down directories for which you intend to throw the results away anyhow. .kde
目录尤其重要,因为它find
浪费时间和I / O带宽来递归查找您打算丢弃结果的目录。 IFS=
and -r
arguments used in the while read
loop, see BashFAQ #1 . while read
循环中使用的IFS=
和-r
参数的重要性的文档,请参阅BashFAQ#1 。 Both of these improve behavior in presence of unusual filenames (clearing IFS prevents trailing whitespace from being stripped; passing -r
prevents literal backslashes from being elided). -r
可以避免省略反斜杠)。 grep -P
-- a GNU extension which is only available if grep
was compiled with libpcre support -- my first cut (prior to moving to find -prune
) switched to grep -E
, which is adequately expressive, much more widely available, and lends itself to higher performance implementations . grep -P
(仅当grep
在libpcre支持下进行编译时才可用的GNU扩展),我的第一个剪切(在移动到find -prune
)切换到了grep -E
,它具有充分的表达能力,可以使用得多并适合更高性能的实现 。 Running your alias after set -x
, we see: 在
set -x
之后运行别名,我们看到:
+ find ./ -type f -printf '%T@ %p\n'
+ grep -vP '/\.\(bash|emacs|gtkrc|kde/|zshrc\)'
+ sort -n
+ tail -10
+ cut -f2- '-d '
+ read EACH
By contrast, running the command it was intended to wrap, we see: 相比之下,运行要包装的命令,我们看到:
+ find ./ -type f -printf '%T@ %p\n'
+ grep -vP '/\.(bash|emacs|gtkrc|kde/|zshrc)'
+ sort -n
+ tail -10
+ cut -f2- '-d '
+ read EACH
In the command itself, there are no literal backslashes before (
and )
. 在命令本身中,
(
和)
之前没有文字反斜杠。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.