我正在尝试创建一个ll
带有awk
管道别名。我试图使用以下答案来逃避撇号。
alias lh= `ll -h | awk {'print $9, \"-\" ,$5, \"-\", $8, \"-\",$7, $6'}`
Run Code Online (Sandbox Code Playgroud)
但它似乎不起作用。
bash
和 的控制台输出结果zsh
是相同的。
awk: cmd. line:1: {print $9, \"-\" ,$5, \"-\", $8, \"-\",$7, $6}
awk: cmd. line:1: ^ backslash not last character on line
awk: cmd. line:1: {print $9, \"-\" ,$5, \"-\", $8, \"-\",$7, $6}
awk: cmd. line:1: ^ syntax error
Run Code Online (Sandbox Code Playgroud)
进入时
alias lh= `ll -h | awk {'print $9, "-" ,$5, "-", $8, "-",$7, $6'}`
Run Code Online (Sandbox Code Playgroud)
输出
意味着空。
您的别名定义存在几个语法问题。ls
然而,第一个问题是强烈建议不要解析 的输出,因为涉及它的代码最终会偶然发现带有“非平凡”字符(例如空格、制表符和换行符)的文件。此外,特别是时间戳的输出格式可能会根据文件实际的“旧”程度而变化,这意味着您可以在输入中包含更多或更少的空格分隔“字段”,具体取决于awk
实际文件,或者一个字段的含义发生变化(例如,从“旧文件”的年份到“最近的文件”的一天中的时间)。这两个方面就是@steeldriver所说的别名“脆弱”。
“明显”的问题是:
=
。这实际上会使别名lh
未定义(至少在bash
)。`
) 中,可能是试图创建“第三层”引用。然而,反引号是命令替换的语法(尽管现在已弃用),即lh
包含管道的控制台输出并尝试将ll | awk ...
其作为命令执行。ll
您依赖于存在或至少预定义为 的别名的命令ls -l
。情况可能是这样,也可能不是。awk
程序启动时单引号和大括号的顺序错误。正确的语法是awk ' { ... } '
.请注意,如果这是 shell 脚本的一部分,您可能需要通过 来运行它(shellcheck
在许多 Linux 发行版上也可以作为独立工具使用),以捕获许多与语法相关的错误。
您遇到的问题的直接解决方案确实是正确的引用和转义。你可以尝试类似的东西
alias lh="ls -lh | awk '{print \$9, \"-\" ,\$5, \"-\", \$8, \"-\",\$7, \$6}'"
Run Code Online (Sandbox Code Playgroud)
其中别名是 中的所有内容" ... "
, 的输入awk
明确声明为ls -lh
,awk
程序用单引号括起来,并且程序内的字段引用awk
受到保护,以免在“别名的定义时”过早解释为 shell 位置参数反斜杠转义(因此awk
实际上将它们视为$9
而不是被 shell 实例的第 9 个位置参数替换,该参数可能为空)。
然而
在您链接的问题的答案之一中找到的建议- 定义一个函数 - 是摆脱“引用地狱”(如@ilkkachu所述)的更好方法,所以类似
lh() { ls -lh | awk '{print $9, "-" ,$5, "-", $8, "-",$7, $6}'; }
Run Code Online (Sandbox Code Playgroud)
更清晰、更容易理解
我建议ls
完全避免解析,并建议使用以下find
基于别名:
lh() { find . -maxdepth 1 -type f ! -name ".*" -printf "%f - %s - %TY - %Td %Tb\n"; }
Run Code Online (Sandbox Code Playgroud)
它使用 的printf
格式化选项来find
可靠地输出所需的文件属性。唯一的缺点是没有-h
人类可读的尺寸选项。
该! -name ".*"
过滤器用于模拟ls
忽略隐藏文件的标准行为。如果您希望列出它们,则可以省略该部分。