xargs가 바이너리 대신 별명을 사용하도록하십시오


13

CentOS 6.5의 Bash 4.2 :

내 안에는 다음을 ~/.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환경에서 별칭을 읽을 수 없습니다?
  • 그렇지 않다면 그렇게 할 수있는 방법이 있습니까?

이 Q & A 에는 원하는 것이 있습니다.
psimon

@ psimon 맞아요, 그것은 본질적으로 해결 방법에서 이미했던 일을 말하고 있습니다 xargs. 명령 에서 별칭을 수동으로 확장해야했습니다 . 내가 찾으려고하는 것은에서 내 별칭을 직접 호출 할 수있는 방법이 있는지입니다 xargs.
MattDMo

1
export GREP_OPTIONS='-n --color=always'xargs 명령 전에 시도 했습니까 ?
doneal24

@ DougO'Neal 감사합니다. 내에 추가하겠습니다 .bash_profile. 답변을 자유롭게 작성하십시오 ...
MattDMo

답변:


10

별명은 정의 된 쉘 내부에 있습니다. 다른 프로세스에서는 볼 수 없습니다. 쉘 기능도 마찬가지입니다. xargs쉘이 아닌 별도의 응용 프로그램이므로 별칭 또는 함수 개념이 없습니다.

xargs가 grep직접 호출하는 대신 쉘을 호출하도록 할 수 있습니다. 그러나 쉘을 호출하는 것만으로는 충분하지 않으므로 해당 쉘에서 별명도 정의해야합니다. 에 별칭이 정의되어 있으면 .bashrc해당 파일을 소싱 할 수 있습니다. 그러나 .bashrc비 대화식 셸에서는 이해가되지 않는 다른 작업을 수행 하면 작동 하지 않을 수 있습니다.

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

정규 표현식을 입력 할 때 중첩 인용의 복잡성을주의하십시오. regexp를 매개 변수로 쉘에 전달하여 수명을 단순화 할 수 있습니다.

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쉘 내부에서 모든 것을 할 수 있습니다. glob 패턴 **/은 디렉토리를 재귀 적으로 탐색합니다. bash에서는 shopt -s globstar이 glob 패턴을 먼저 활성화 하기 위해 실행해야합니다 .

grep regex_here **/*.py

몇 가지 제한 사항이 있습니다.

  • 많은 파일이 일치하거나 긴 경로를 가진 경우 최대 명령 줄 길이를 초과하여 명령이 실패 할 수 있습니다.
  • bash ≤4.2 (최신 버전이나 ksh 또는 zsh는 아님)에서 **/디렉토리에 대한 심볼릭 링크로 반복됩니다.

또 다른 방법은 MariusMatutiae에서 제안한대로 프로세스 대체사용하는 것 입니다.

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

**/적용 할 수없는 경우에 유용합니다 . 복잡한 find표현식의 경우 또는 bash ≤4.2에서 심볼릭 링크 아래에서 재귀하지 않으려 는 경우에 유용 합니다. 공백이 포함 된 파일 이름이 끊어집니다. 해결 방법은 globbing설정 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

관련 SO 질문 에서 찾을 수없는 다른 접근법의 데모로 이것을 사용하십시오 .

xargs첫 번째 인수가 별명인지 확인하고 적절하면 확장 하는 랩퍼 함수를 ​​작성할 수 있습니다 .

여기에 있음을 정확히 수행하지만 불행히도 그것은 필요로하는 코드 Z 쉘을 bash는 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 : # data = test
foo / bar.p1 : 122 : # data = test # 줄 번호 포함
zsh % unalias grep 
zsh % find foo -name "* .p *"| xargs grep -E 테스트
foo / bar.p0 : # data = test
foo / bar.p1 : # data = test # 줄 번호는 포함되지 않습니다
zsh % 

1

더 간단하고 우아한 솔루션은 프로세스 대체 를 사용 하는 것입니다 .

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

파이프처럼 새 쉘을 만들지 않습니다. 즉, 별칭이 정의 된 원래 쉘에 있고 출력이 원하는대로됩니다.

리디렉션과 괄호 사이에 공백이 없도록주의하십시오. 그렇지 않으면 bash가 오류를 발생시킵니다. 내가 아는 한, 프로세스 대체는 Bash, Zsh, Ksh {88,93}에 의해 지원되지만 pdksh에 의해 지원 되지않는다 (아직 말하면 안된다고 들었다 ).


pdksh 개발이 죽었다고 생각합니다. Mksh는 " 후속적인 프로젝트로 파싱 ​​컨셉은 tg @ 's 헤드에서 이루어지고있다" 라는 후계 프로젝트 이다.
Gilles 'SO- 악한 중지'

프로세스 대체는 복잡한 find명령에 대한 좋은 방법 이지만 공백을 깰 find | xargs수 있고 ( -print0및 로 전환 -0하거나를 사용하여 -exec) 가능한 한 쉽게 수정할 수는 없다는 점에주의해야합니다 . 해당되는 경우 **/더 간단하고 강력합니다.
Gilles 'SO- 악마 그만해'

0

grep은 환경 변수 GREP_OPTIONS에서 기본 옵션 세트를 읽습니다. 당신이 넣을 경우

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

.bashrc에서 변수는 서브 쉘로 전달되어 예상 결과를 얻을 수 있습니다.


그러나 넣지 마십시오 --line-number또는 --color=always에서 GREP_OPTIONS단지 하나 개의 명령이 아니라면,이 스크립트를 많이 끊어집니다. --color=auto거기에 있어도 괜찮습니다. 그게 전부입니다. 이 줄을 넣으면 .bashrc많은 것들이 깨질 것입니다.
Gilles 'SO- 악한 중지'

@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 'SO- 악한 중지'

@Gilles 나는 이와 같은 많은 스크립트를 알고 있습니다. 내가 갈 수없는 것은 일반적으로 /etc/init.d/cron과 같은 루트에 의해서만 실행됩니다. 개인적으로, 나는이없는 모든 내 사용자 계정에 정의 된 별칭을도 내가 명령의 기본 동작을 재정의하는 rc 파일 또는 환경 변수를 통해 옵션을 설정 않습니다. 편의성보다 예측 가능성을 선호합니다.
doneal24

별칭은 스크립트에서 보이지 않기 때문에 예측 가능성을 깨뜨리지 않습니다. 설정하면 (설계 목적 GREP_OPTIONS과 같은) 몇 가지 옵션을 제외하고 예측 성이 매우 나빠 --color=auto집니다.
Gilles 'SO- 악마 그만해'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.