Нехай xargs використовують псевдонім замість двійкового


14

Bash 4.2 на CentOS 6.5:

У ~/.bash_profileмене є купа псевдонімів, зокрема:

alias grep='grep -n --color=always'

щоб я міг отримати підсвічування кольорів та автоматично друкувати номери рядків під час роботи grep. Якщо я виконую наступне, виділення робіт, як очікувалося:

$ grep -Re 'regex_here' *.py

Однак, коли я нещодавно запускав це:

$ find . -name '*.py' | xargs grep -E 'regex_here'

результати не було виділено, а номери рядків не друкувалися, що змусило мене повернутися назад і явно додати -n --color=alwaysдо grepкоманди.

  • Чи xargsне читає псевдоніми в оточенні?
  • Якщо ні, чи є спосіб зробити це?

У цьому питанні є те, що ви хочете.
psimon

@psimon вірно, це по суті говорить про те, щоб зробити те, що я вже робив у своєму вирішенні - мені довелося вручну розгорнути псевдонім у xargsкоманді. Я намагаюся з’ясувати, чи є спосіб, з якого я можу безпосередньо назвати свій псевдонім xargs.
MattDMo

1
Ви пробували export GREP_OPTIONS='-n --color=always'перед командою xargs?
doneal24

@ DougO'Neal дякую, що спрацювало! Я додам це до свого .bash_profile. Не соромтесь написати відповідь ...
MattDMo

Відповіді:


11

Псевдонім є внутрішнім для оболонки, де він визначений. Це не видно для інших процесів. Те саме стосується функцій оболонки. xargsце окрема програма, яка не є оболонкою, тому не має поняття псевдонімів або функцій.

Ви можете змусити xargs викликати оболонку, а не викликати grepбезпосередньо. Однак лише виклик оболонки недостатньо, ви також повинні визначити псевдонім у цій оболонці. Якщо псевдонім визначений у вашому .bashrc, ви можете джерело цього файлу; однак це може не спрацювати, якщо .bashrcвиконуються інші завдання, які не мають сенсу в неінтерактивній оболонці.

find . -name '*.py' | xargs bash -c '. ~/.bashrc; grep -E regex_here "$@"' _

Остерігайтеся тонкощів вкладеного цитування під час введення повторного тексту. Ви можете спростити своє життя, передавши регулярний параметр як параметр оболонці.

find . -name '*.py' | xargs bash -c '. ~/.bashrc; grep -E "$0" "$@"' regex_here

Ви можете виконати пошук псевдоніму явно. Тоді xargsпобачимо grep -n --color=always.

find . -name '*.py' | xargs "${BASH_ALIASES[grep]}" regex_here

В zsh:

find . -name '*.py' | xargs $aliases[grep] regex_here

До речі, зауважте, що find … | xargs … перерви на імена файлів, що містять пробіли (серед інших) . Ви можете виправити це, змінивши на нульові записи:

find . -name '*.py' -print0 | xargs -0 "${BASH_ALIASES[grep]}" regex_here

або використовуючи -exec:

find . -name '*.py' -exec "${BASH_ALIASES[grep]}" regex_here {} +

Замість того, щоб дзвонити find, ви можете робити все цілком всередині оболонки. Глобальний шаблон реверсивно **/переміщує каталоги. У bash, вам потрібно запустити, shopt -s globstarщоб спочатку ввімкнути цей шаблон.

grep regex_here **/*.py

Це має кілька обмежень:

  • Якщо багато файлів збігаються (або якщо вони мають довгі шляхи), команда може вийти з ладу, оскільки вона перевищує максимальну довжину командного рядка.
  • У bash ≤4.2 (але не в останніх версіях, ні в ksh чи zsh) **/повторюється переклад у символічні посилання на каталоги.

Інший підхід полягає у використанні процесу заміщення, як це запропонував MariusMatutiae .

grep regex_here <(find . -name '*.py')

Це корисно, коли **/це не застосовується: для складних findвиразів або в bash ≤4.2, коли ви не хочете повторюватися за символічними посиланнями. Зауважте, що це перерва на імена файлів, що містять пробіли; вирішення завдання полягає у встановленні IFSта відключенні глобалізації , але воно починає трохи складніше:

(IFS=$'\n'; set -f; grep regex_here <(find . -name '*.py') )

дякую за чітке пояснення того, чому псевдоніми не видно для інших процесів
MattDMo

Можна також використовувати процес заміщення, дивіться мою відповідь.
MariusMatutiae

11

Використовуйте alias xargs='xargs '

alias: alias [-p] [name[=value] ... ]
(snip)
A trailing space in VALUE causes the next word to be checked for
alias substitution when the alias is expanded.

Дякую за це, я не знав про простудний космічний трюк.
MattDMo

Np. Також корисно з sudo
1.61803

2

Будь ласка, сприйміть це як демонстрацію іншого підходу, якого я не можу знайти у відповідному питанні про так :

Ви можете написати функцію обгортки, xargsяка перевіряє, чи є перший аргумент псевдонімом, і якщо так, розгорніть їх відповідно.

Ось код, який робить саме це, але, на жаль, він вимагає оболонки Z, а значить, не працює 1: 1 з bash (і, чесно кажучи, я не звик бити достатньо, щоб перенести його):

xargs () {
        local expandalias
        if [[ $(which $1) =~ "alias" ]]; then
                expandalias=$(builtin alias $1) 
                expandalias="${${(s.'.)expandalias}[2]}"
        else
                expandalias=$1
        fi
        command xargs ${(z)expandalias} "${(z)@[2,-1]}"
}

Доказ того, що він працює:

zsh% alias grep = "grep -n" ´                           # включає номер рядка відповідності
zsh% find foo -name "* .p *" | xargs grep -E тест
foo / bar.p0: 151: # дані = тест
foo / bar.p1: 122: # дані = тест # номери рядків включені
zsh% unalias grep 
zsh% find foo -name "* .p *" | xargs grep -E тест
foo / bar.p0: # дані = тест
foo / bar.p1: # data = test # номери рядків не включені
zsh% 

1

Більш простим і елегантним рішенням є використання процесу заміщення :

grep -E 'regex_here' <( find . -name '*.py')

Він не створює нову оболонку, як це робить труба, а це означає, що ви все ще знаходитесь в оригінальній оболонці, де визначено псевдонім, і вихід саме такий, який ви хочете.

Будьте обережні, щоб не залишалося місця між перенаправленням і дужками, інакше bash призведе до помилки. Наскільки мені відомо, процес заміщення підтримується Bash, Zsh, Ksh {88,93}, але не pdksh (мені кажуть, що це ще не повинно бути ).


Я думаю, що розвиток pdksh мертвий. Mksh - це більш-менш наступний проект - «виявляється досить важко (концепція розбору робиться в голові tg @)» .
Жил "ТАК - перестань бути злим"

Підстановка процесів є метод хороший для складних findкоманд, але ви повинні остерігатися , що розіб'ю на просторах, і які не можуть бути виправлені так легко , як find | xargsможе бути ( за рахунок переходу до -print0і -0, або з допомогою -exec). За наявності, **/це простіше і надійніше.
Жил "ТАК - перестань бути злим"

0

grep прочитає набір параметрів за замовчуванням із змінної середовища GREP_OPTIONS. Якщо ви поставите

 export GREP_OPTIONS='--line-number --color=always'

у вашому .bashrc, тоді змінна буде передана підскладам, і ви отримаєте очікувані результати.


Але не ставте --line-numberабо --color=alwaysв , GREP_OPTIONSякщо це не тільки для однієї команди, це порушить багато сценаріїв. --color=autoце нормально там, і це приблизно все. Якщо .bashrcпоставити цю лінію у свою чергу, ви зламаєте багато речей.
Жил "ТАК - перестань бути злим"

@Gilles Налаштування псевдонімів або переопределення параметрів за замовчуванням для будь-якої команди для кореневого облікового запису - це погано. Налаштування цих параметрів для облікового запису користувача навряд чи спричинить багато проблем. Я не можу придумати будь-які сценарії користувачів, які є проблемними.
doneal24

Практично про будь-який скрипт, який використовує grep таким чином, що виходить за межі тестування, наявність події порушиться. Наприклад, з /etc/init.d/cronмоєї системи: value=`egrep "^${var}=" "$ENV_FILE" | tail -n1 | cut -d= -f2` . Або з /usr/bin/pdfjam: pdftitl=`printf "%s" "$PDFinfo" | grep -e … | sed -e …` . Псевдонім не є проблемою, оскільки його не бачать у сценаріях.
Жил "ТАК - перестань бути злим"

@Gilles Я знаю багато подібних сценаріїв. Ті, яких я не можу обійти, як правило, виконуються лише корінь (як-от /etc/init.d/cron). Особисто у мене немає жодних псевдонімів, визначених у моїх облікових записах користувачів, і я не встановлюю параметри у файлі rc або за допомогою змінних оточення, щоб змінити поведінку команд за замовчуванням. Я віддаю перевагу передбачуваності перед зручністю.
doneal24

Псевдоніми не порушують передбачуваність, оскільки їх сценарії не бачать. Встановлення GREP_OPTIONSпередбачуваності перерв дуже погано, за винятком декількох варіантів на кшталт --color=auto(для чого він був розроблений)
Жил 'ТАК - перестань бути злим'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.