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.