2

I am trying to create an ll with awk pipe alias. I am trying to escape the apostrophes using the following answers.

alias lh= `ll -h | awk {'print  $9, \"-\" ,$5, \"-\", $8, \"-\",$7, $6'}` 

But it doesn't appear to work.

The resulting console output for bash and zsh is the same.


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

When entering

alias lh= `ll -h | awk {'print  $9, "-" ,$5, "-", $8, "-",$7, $6'}`

the output is meaning empty.

1
  • 1
    Is ll on your system an alias for ls -l or is it something else?
    – Ed Morton
    Commented Feb 22, 2023 at 21:25

1 Answer 1

8

There are several syntax issues with your alias definition. However, the first problem is that parsing the output of ls is strongly discouraged because code that involves it will ultimately stumble upon files with "non-trivial" characters such as spaces, tabs and newlines. In addition, in particular the output format of the timestamp may change depending on how "old" the file actually is, meaning that you can have more or less space-separated "fields" in the input to awk depending on the actual file, or one of the fields changing its meaning (e.g. from year in case of an "old file" to time of the day for a "recent file"). These two aspects are what @steeldriver referred to as the alias being "fragile".

The "obvious" issues are:

  1. You have a space behind the =. This will actually make the alias lh undefined (at least in bash).
  2. You enclosed the alias definition in backticks (`), probably in an attempt to create a "third layer" of quoting. However, backticks are the (albeit now deprecated) syntax for command substitution, i.e. lh would contain the console output of the ll | awk ... pipeline and try to execute that as a command.
  3. You rely on a command ll being either present or at least pre-defined as an alias of ls -l. This may or may not be the case.
  4. Your awk program starts has the single-quotes and the curly braces in the wrong order. The correct syntax is awk ' { ... } '.

Note that if this is part of a shell script, you may want to run it through shellcheck, also available as standalone tool on many Linux distributions, to catch many syntax-related errors.

The immediate solution to the problem you experience is indeed the correct quoting and escaping. You could try something like

alias lh="ls -lh | awk '{print  \$9, \"-\" ,\$5, \"-\", \$8, \"-\",\$7, \$6}'"

where the alias is everything in the " ... ", the input to awk is explicitly stated as ls -lh, the awk program is enclosed in single quotes, and the field references inside the awk program are protected from premature interpretation as shell positional parameters at "definition-time of the alias" by backslash-escaping (so that awk actually sees them as $9 and not replaced by the 9th positional parameter of the shell instance, which is likely empty).

However

  • the advice found in one of the answers to the question you linked - defining a function - is a far better way to get out of the "quoting hell" (as mentioned by @ilkkachu), so something like

    lh() { ls -lh | awk '{print  $9, "-" ,$5, "-", $8, "-",$7, $6}'; }
    

    is much cleaner and easier to understand

  • I would recommend to avoid parsing ls altogether, and propose the following find-based alias instead:

    lh() { find . -maxdepth 1 -type f ! -name ".*" -printf "%f - %s - %TY - %Td %Tb\n"; }
    

    which uses the printf formatting options of find to reliably output the desired file properties. The only drawback is that there is no -h option for human-readable sizes.

    The ! -name ".*" filter is used to emulate the standard behavior of ls to ignore hidden files. If you want them listed, you can leave that part out.

2
  • Would it be possible to create an if command for %s to divide by factors of 8 depending on the size e.g. 8bit = 1byte and so on?
    – zerberus
    Commented Feb 23, 2023 at 13:05
  • @zerberus As per this Q&A, unfortunately it doesn't seem possible to teach find that trick. You could post-process the output and pipe it through numfmt, but that would somewhat defeat the purpose of using the find command in the first place (i.e. not having to post-process output that may contain unusual characters in the file names).
    – AdminBee
    Commented Feb 23, 2023 at 13:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .