Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.bashrc中的别名失败,而命令行成功_Bash_Shell_Alias - Fatal编程技术网

.bashrc中的别名失败,而命令行成功

.bashrc中的别名失败,而命令行成功,bash,shell,alias,Bash,Shell,Alias,我从用户的home dir运行此命令,以显示最新的文件,同时忽略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; 这是可行的,但如果将其作为别名放置在my.bashrc中,效果就不一样了: alias recentfi

我从用户的home dir运行此命令,以显示最新的文件,同时忽略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;
这是可行的,但如果将其作为别名放置在my.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;'
在图像中,您可以看到不进行任何过滤的结果,然后是使用
grep-v
进行过滤的所需结果,该过滤在命令行上运行。最后的结果是,仅部分成功地清除了这些文件

我试过使用bash和[b]ash。甚至连bas(它甚至不能得到.basin)的工作都没有?!?我也可以使用macs或acs,但仍然可以省略.emacs,因此很明显,我的别名中的语法不尊重/。任何一个这不是我最初认为的保留字的问题

如果我将原始命令原样放在文件中,然后以这种方式使用别名,我确实会得到预期的结果: 别名recentfiles='/root/myCommand/recentfiles'


有人能给我解释一下,或者给我指一个参考资料,让我明白这里在起什么作用吗?我不知道要搜索哪个短语的正确术语。

这应该可以解决您的问题:

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;'
问题在于
grep-p
,其中-p使用perl正则表达式。在perl中,分组时不需要使用\。所以
(bash | emacs |…)
而不是
\(bash | emacs |…\)
。我真的怀疑它是否在.bashrc之外工作,除非你有
grep
的别名,这使得它在
.bashrc
之外的行为有所不同

正如其他人在评论中所说,您的过滤效率低下。最好使用以下命令重写命令:

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;
这样,它就不会浪费时间在
.emacs.d/
.kde/
内搜索文件,并且会立即删除搜索。而且,
xargs-0ls-l
比while循环更短、更清晰

要避免包含换行符的文件名出现问题,最好使用\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
第1部分:解决问题 改用函数。

别名有几个主要问题:

  • 由于在创建别名时将内容传递给引号内的字符串前缀,因此其解析方式与直接在命令行中键入时不同

  • 因为别名是简单的前缀替换,所以它们没有自己的参数(
    $1
    $2
    ,等等);它们没有调用堆栈;调试机制,如
    PS4=':$BASH_SOURCE:$LINENO+;set-x
    无法告诉您别名中的文件代码来自哪个文件;等等

  • 别名是一种交互式功能;POSIX根本不要求shell支持它们,并且在脚本执行过程中默认关闭它们

函数解决了所有这些问题

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 --
}
请注意,我还做了一些其他更改:

  • 上面的代码没有使用
    \n
    作为分隔符,而是使用
    \0
    。这是因为可以在文件名中找到换行符;对于管道的其余部分来说,名称中包含换行符的文件可以像任意数量的文件一样,具有任意大小。(不幸的是,POSIX不要求
    sort
    tail
    支持换行分隔符,因此上面使用的
    -z
    选项是GNUISM)
  • 我没有使用
    grep-v
    删除点文件,而是使用
    -prune
    选项
    查找
    。这对于像
    .kde
    这样的目录尤其重要,因为它阻止了
    find
    花费时间和I/O带宽来递归您打算丢弃结果的目录
  • 有关读取时
    循环中使用的
    IFS=
    -r
    参数重要性的文档,请参阅。这两种方法都可以改善出现异常文件名时的行为(清除IFS可以防止删除尾随空格;传递
    -r
    可以避免删除文字反斜杠)
  • 而不是
    grep-P
    ——只有在
    grep
    使用libpcre支持编译时才可用的GNU扩展——我的第一个剪切(在移动到
    find-prune
    之前)切换到
    grep-E
    ,它具有充分的表达能力,可用性更广,并且更具可扩展性

第二部分:解释问题 在
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
相比之下,运行它要包装的命令时,我们看到:

+ find ./ -type f -printf '%T@ %p\n'
+ grep -vP '/\.(bash|emacs|gtkrc|kde/|zshrc)'
+ sort -n
+ tail -10
+ cut -f2- '-d '
+ read EACH

在命令本身中,

之前没有文字反斜杠,为什么不告诉
查找
来过滤掉这些反斜杠呢?改用函数;)创建别名意味着shell将扫描该命令行,并对单引号和dbl引号的字符串进行处理。在通过处理激活cmd字符串之后,很难理解它处于什么“状态”(使用了什么引号和转义字符,哪些仍然存在)。修复别名真的不值得花时间,最好使用函数,它们是可调试的,它们可以接受运行时参数,并且不必欺骗shell解析器来让它们工作。好的,祝你好运。使用
\(-name.bash-o-name.emacs-o…\)
find
命令中,而不是
grep
。当您编写“在图像中,您看到了”时,我假设您试图发布图像,但不知何故无法发布。这很好,直接复制粘贴终端输出要好得多。
xargs ls-l
会对带有空格的文件名产生错误行为:如果您有一个名为
foo bar
的文件,您将运行
ls-l“foo”“bar”
。至少应使用
xargs-d$'\n'ls-l
来更正带有空格或引号的文件名;最好重写管道的其余部分,以使用NUL分隔符,以便对具有文字换行符的文件名也是正确的。Y