이 명령을 작동시키는 방법:
ls * | xargs -I {} sh -c 'echo {}; awk '{print $1}' {} | uniq'
간단한 작업을 수행해야 합니다. uniq
첫 번째 열의 폴더에 있는 각 파일의 이름과 값을 인쇄합니다.
$
기호가 문자열 기호의 끝으로 인식되고 따옴표와 관련이 있기 때문에 작동하지 않습니다 .
에러 메시지:
awk: cmd. line:1: {print
awk: cmd. line:1: ^ unexpected newline or end of string
답변1
두 번째 작은따옴표는 첫 번째 작은따옴표 문자열을 종료합니다 'echo {}; awk '
. 그런 다음 {print $1}
따옴표를 풀고 또 다른 작은 따옴표로 묶은 string 입니다 ' {} | uniq'
. 이는 구문 강조가 있는 모든 편집기에서 명확해야 합니다. 질문의 구문 강조를 보면 명확합니다.
여기서 가장 간단한 접근 방식은 중첩된 참조를 완전히 피하는 것입니다. awk 스크립트를 매개변수로 sh
.
xargs -I {} sh -c 'echo "$1"; awk "$0"' '{print $1}' {} | uniq'
(또한 {}
스크립트 내부를 해당 인수로 대체했습니다 sh
. {}
스크립트 내부에서는 절대 사용하지 마십시오. 파일 이름이 아닌 셸 구문으로 구문 분석되므로 셸 특수 문자가 포함된 파일 이름에서는 치명적으로 실패합니다.)
작은 따옴표 리터럴 내에 작은 따옴표를 효과적으로 포함하려면 다음을 사용하십시오 '\''
(공식적으로 이는 작은 따옴표 리터럴을 종료한 다음 이전 백플래시로 인해 문자 그대로 해석되는 작은 따옴표를 추가한 다음 다른 작은 따옴표 리터럴을 시작합니다. 그러나 효과는 다음과 같습니다. 똑같다).
xargs -I {} sh -c 'echo {}; awk '\''{print $1}'\'' {} | uniq'
또는 한 수준에서는 작은따옴표를 사용하고 다른 수준에서는 큰따옴표를 사용하지만 이는 더 까다로워집니다.
ls *
(내 생각엔 당신의 말도 안되는 명령은 단지 극도로 단순화된 예일 뿐입니다. )
답변2
xargs
전혀 그럴 필요가 없습니다.
이 사이트의 다른 곳에서 읽은 것처럼(죄송합니다. 어디인지 기억이 나지 않습니다) 상위 사용자의 글은 다음과 같습니다.
네,
xargs
정말 멋진 장난감이에요. 아니요, 사용할 필요는 없습니다.
이것:
ls * | xargs -I {} sh -c 'echo {}; awk '{print $1}' {} | uniq'
할 수 있다완전한 교체이것으로:
for f in *; do echo "$f"; awk '{print $1}' "$f" | uniq; done
이것은 당신에게 중요한 것을 제공합니다안전가독성과 실제 기능은 말할 것도 없고 이전 버전에 비해 개선되었습니다. (물론 첫 번째 버전은 작은따옴표를 중첩하려고 했기 때문에 전혀 작동하지 않습니다.**.)
그러나 버전의 참조를 수정하더라도 자신을 활짝 열린 입장에 두는 것입니다. 임의의 파일 이름을 쉘 명령에 입력 -c
하여효과적으로해당 파일 이름 eval
등에서 실행하십시오.악용 가능한 취약점이 많다특정 파일 이름을 만드십시오. 예를 들어, touch ';rm -rf "$HOME" #'
이로 인해 홈 디렉터리가 삭제됩니다.
옵션 플래그로 해석될 수 있는 파일 이름을 포함하여 이상한 파일 이름의 처리를 완전히 보장하려면 awk
다음 명령을 사용하십시오.
for f in *; do printf '%s\n' "$f"; awk '{print $1}' < "$f" | uniq; done
답변3
두 가지 주요 질문이 있습니다.
파이프 입구가 완전히 잘못
ls *
되었습니다xargs
. 그것~ 할 것이다파일 이름에 공백, 개행 문자, 쉘 와일드카드가 포함되어 있거나 (실행 항목에 따라xargs
)-
.대신 사용하십시오
find ... -print0 | xargs -0
.중첩된 따옴표. @Gilles가 그의 답변에서 언급했듯이 이를 올바르게 수행하는 몇 가지 방법이 있지만매우여러 겹의 중첩된 따옴표가 있으면 길을 잃거나 혼란스러워지기 쉽습니다. 성공하더라도 지금부터 6개월은 고사하고 내일 코드를 (쉽게) 읽거나 이해하지 못할 수도 있습니다.
이것은많은원하는 작업을 수행하는 스크립트를 작성하고 xargs를 사용하여 실행하는 것이 더 쉽습니다.
스크립트가 여러 파일 이름 인수와 독립적으로 작동하는 경우 xargs
이를 사용하지 않고도 작동 할 것입니다 -I {}
(즉, -L 1
.FreeBSD 버전 xargs
에도 해당 문제를 피할 수 있는 옵션이 있음 을 의미합니다 -J
).
예를 들어, myscript.sh
:
#! /bin/sh
for f in "$@" ; do
echo "$f"
awk '{ print $1 }' -- "$f" | uniq
done
( awk
내가 이해하려고 노력한 대부분의 버전은 --
처리 중지 옵션 args를 의미합니다. 이는 original-awk
freebsd와 동일하지 않습니다. 그렇지 않은 경우 명령줄에서 제거하십시오.)awk
awk
awk
다음과 같이 실행하세요.
./myscript.sh *
*
하위 디렉터리 및 파일과 일치합니다 .
또는 다음과 같습니다:
find . -maxdepth 1 -type f -print0 | xargs -0r /path/to/myscript.sh
또는
find . -maxdepth 1 -type f -exec /path/to/myscript.sh {} +
이 두 가지는 현재 디렉터리의 일반 파일만 처리합니다.
입력 파일이 미리 정렬되지 않은 경우 sort -u
대신 uniq
.