Unix 'alias' не работает с командой awk

Я создаю псевдоним в Unix и обнаружил, что следующая команда не работает.

alias logspace='find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | awk '{print $5, $9 }''

Я получаю следующее:

awk: cmd. line:1: {print
awk: cmd. line:1:       ^ unexpected newline or end of string

Любые идеи о том, почему сбойной команды awk не удается...

Спасибо, Shaun.

Ответ 1

В дополнение к полезному ответу @Dropout:

ТЛ; др

Проблема заключается в попытке OP использовать ' внутри ' строку -enclosed (в одинарных кавычках).

Наиболее надежное решение в этом случае - заменить каждый интерьер ' на '\'' (sic):

alias logspace='find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | 
                awk '\''{print $5, $9 }'\'''
  • Борновоподобные (POSIX-совместимые) оболочки не поддерживают использование ' char внутри строк в одинарных кавычках ('...' -enclosed) вообще - даже с экранированием.
    • (В отличие от этого, вы МОЖЕТЕ избежать " внутри строки в двойных кавычках как \", и, как и в ответе @Droput, вы можете напрямую встраивать символы ' там., Но смотрите ниже о подводных камнях.)
  • Решение выше, эффективно создает строку из нескольких, одиночных кавычек, в которые в буквальном смысле ' символов. - выходит за пределы строк в одинарных кавычках как \' - вставляется в.
    Другой способ выразить это, как это сделал @Etan Reisinger в комментарии: '\'' означает "закрыть строку", "экранировать одинарную кавычку", "начать новую строку".
  • При определении псевдонима вы обычно хотите заключить его в одинарные кавычки, чтобы задержать оценку команды до тех пор, пока не будет вызван псевдоним.

Другие решения и их подводные камни:

Ниже обсуждаются альтернативные решения, основанные на следующем псевдониме:

alias foo='echo A '\''*'\'' is born at $(date)'

Обратите внимание, что * эффективно заключен в одинарные кавычки, используя метод выше, чтобы предотвратить расширение имени пути, когда псевдоним вызывается позже.

При вызове этот псевдоним печатает буквально A * star is born, за которой следуют текущая дата и время, например: A * is born at Mon Jun 16 11:33:19 EDT 2014.


Используйте функцию под названием ANSI C, заключающую в кавычки те оболочки, которые ее поддерживают: bash, ksh, zsh

ANSI C-строка в кавычках, которые заключены в $'...', ПОЗВОЛЯЕТ избежать внедренных ' символов. как \':

alias foo=$'echo A \'*\' is born at $(date)'

Подводные камни:

  • Эта функция не является частью POSIX.
  • По замыслу escape-последовательности, такие как \n, \t ,..., также интерпретируются (фактически, цель функции).

Использование чередующихся стилей цитирования, как в ответе @Dropout:

Ловушка:

'...' и "..." имеют разную семантику, поэтому замена одной на другую может иметь непредвиденные побочные эффекты:

alias foo="echo A '*' is born at $(date)" # DOES NOT WORK AS INTENDED

Несмотря на синтаксическую корректность, это НЕ будет работать должным образом, потому что использование двойных кавычек заставляет оболочку сразу развернуть подстановку команд $(date) и, таким образом, жестко связывает дату и время во время определения псевдонима с псевдонимом.

Как указано: при определении псевдонима вы обычно хотите заключить его в одинарные кавычки, чтобы задержать оценку команды до вызова псевдонима.


Наконец, предостережение:

Хитрость в среде оболочки, похожей на Bourne, заключается в том, что встраивание ' внутри строки в одинарных кавычках иногда - ложно - НАХОДИТСЯ работать (вместо генерирования синтаксической ошибки, как в вопросе), когда вместо этого происходит что-то другое:

 alias foo='echo a '*' is born at $(date)'  # DOES NOT WORK AS EXPECTED.

Это определение принято (без синтаксической ошибки), но не будет работать должным образом - правая часть определения эффективно анализируется как 3 строки - 'echo a ', * и ' is born at $(date)', что из-за того, как оболочка анализирует строку (объединение смежных строк, удаление кавычек), приводит к следующей единственной литеральной строке: a * is born at $(date). Так как * в заключительном определении псевдонима не заключен в кавычки, он будет расширен до списка всех имен файлов/каталогов в текущем каталоге (расширение имени пути) при вызове псевдонима.

Ответ 2

Вы можете использовать разные кавычки для окружения всего текста и внутренних строк.

Попробуйте изменить его на

alias logspace="find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | awk '{print $5, $9 }'"

Другими словами, ваши внешние кавычки должны отличаться от внутренних, поэтому они не смешиваются.

Ответ 3

Обновление сообщества wiki:

  • Функция выкупа этого распознает, что проблема OP заключается в неэкранированном использовании разделителей строк (') внутри строки.
  • Тем не менее, этот ответ содержит общие истины для обработки строк, но НЕ применим к (shell-совместимому, POSIX-совместимому) программированию оболочки специально и, таким образом, не адресует проблему OP напрямую - см. комментарии.

Примечание. Фрагменты кода предназначены для псевдокода, а не для языка оболочки.

Основные строки: вы не можете использовать одну и ту же цитату внутри строки, так как вся строка разделяется символом:

foo='hello, 'world!'';
    ^--start string
            ^-- end string
             ^^^^^^^^--- unknown "garbage" causing syntax error.

Вам нужно избежать внутренних строк:

foo='hello, \'world!\'';
            ^--escape

Это справедливо в отношении языка программирования КАЖДЫЙ на планете. Если они не обеспечивают механизмы экранирования, такие как \, тогда вам нужно использовать альтернативные средства, например.

quotechar=chr(39); // single quote is ascii #39
foo='hello ,' & quotechar & 'world!' & quotechar;

Ответ 4

Избегайте знака $ не одиночных кавычек awk, и используйте двойные кавычки для псевдонима.

Попробуй это:

alias logspace="find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | awk '{print \$5, \$9 }'"