Использование | символ канала из переменной $ делает его еще одним аргументом в bash; как избежать этого?

8

У меня есть такой скрипт

export pipedargument="| sort -n"
ls $pipedargument

Но это дает ошибку

ls: |: No such file or directory
ls: sort: No such file or directory

Кажется, это воспринимает содержание "| sort -n"как просто аргумент, переданный ls.

Как я могу избежать этого, чтобы он воспринимался как обычная команда?

Я пытаюсь условно установить $pipedargument. Я думаю, что я мог бы просто условно выполнить разные версии команды, но все еще задаюсь вопросом, есть ли способ заставить эту работу как выше?

laggingreflex
источник

Ответы:

9

Вы правы, что не можете использовать |этот способ. Причина в том, что оболочка уже искала конвейеры и разделяла их на команды перед тем, как выполнить подстановку переменных. Следовательно, |трактуется как просто еще один персонаж.

Один из возможных обходных путей - поместить символ канала буквально:

$ cmd="sort -n"
$ ls | $cmd

В случае, если вам не нужен конвейер, вы можете использовать catв качестве «nop» или заполнителя:

$ cmd=cat
$ ls | $cmd

Этот метод позволяет избежать тонкостей eval . Смотрите также здесь .

Лучший подход: массивы

Более сложный подход будет использовать bashмассивы вместо простых строк:

$ cmd=(sort -n)
$ ls | "${cmd[@]}"

Преимущество массивов становится важным, как только вам нужна команда, cmdсодержащая аргументы в кавычках.

John1024
источник
Не могли бы вы уточнить, зачем нужны массивы в случае цитируемых аргументов? Я столкнулся с этим, но не совсем понимаю, почему это не работает.
worieux
@anxieux Короткий ответ заключается в том, что кавычка, находясь внутри строки оболочки, теряет всю свою синтаксическую силу для группировки слов и вместо этого обрабатывается как любой другой символ. Более длинное и отличное обсуждение этой проблемы см .: я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу! ,
John1024
5

Вы можете evalиспользовать команду:

eval "ls $pipedargument"

или даже лучше определить функцию как:

sorted() { "$@" | sort -n; }

и позже вызовите это с желаемыми аргументами:

sorted ls /tmp
jimmij
источник
Другим вариантом было бы определить псевдоним:alias ls='ls | sort -n'
thiagowfx
0

Я бы использовал функцию для этого. Что-то вроде:

### usage pipedargument cmd args ###

pipedargument()
{
    sort -n <<< "$( "$@" )"
}

$ pipedargument /sbin/ifconfig eth0
      RX bytes:5904986765 (5.4 GiB)  TX bytes:714370767 (681.2 MiB)
      RX packets:5981427 errors:0 dropped:0 overruns:0 frame:0
      TX packets:4403989 errors:0 dropped:0 overruns:0 carrier:0
      UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
      collisions:0 txqueuelen:1000 
      inet addr:XXX.XXX.X.XX  Bcast:XXX.XXX.X.XXX  Mask:255.255.255.0
      inet6 addr: xx00::0x0x:00xx:xx0:000/00 Scope:Link
eth0      Link encap:Ethernet  HWaddr 0x:0x:00:x0:00:00
grepper
источник