readlink와 같은 일부 프로그램이 파이프에서 입력을 받을 수 없는 이유는 무엇입니까?

readlink와 같은 일부 프로그램이 파이프에서 입력을 받을 수 없는 이유는 무엇입니까?

$PATH편집하려는 파일의 스크립트를 가리키는 심볼릭 링크가 있습니다. 파일 경로를 잊어버려서 다음을 시도해 보았습니다.

$ which my_script_link | readlink

출력 파일 경로를 예상했지만 출력됩니다.

> readlink: missing operand
> Try 'readlink --help' for more information

이전에 다른 상황(예: 편집을 위해 파일 목록을 vim으로 파이프하는 등)에서도 유사한 동작을 본 적이 있습니다. subshell 과 같은 해결 방법이 있다는 것을 알고 있지만 readlink $(which my_script_link)이해하고 싶습니다.이 경우 파이프라인이 내가 상상한 대로 작동하지 않습니다.

감사해요!

답변1

간단히 말해서, 이를 수행하도록 프로그램이 작성되지 않았기 때문입니다. 소프트웨어가 STDIN에서 읽을 수 있는지 또는 입력 파일이 필요한지 여부를 결정하는 것은 프로그래머의 몫입니다. 이 경우 readlink해당 man페이지에는 다음과 같이 명시되어 있습니다(강조).

readlink - 인쇄가 해결됨심볼릭 링크또는 규범적인파일 이름

요약
읽기 링크 [옵션]...문서...

일반적으로 STDIN에서 입력을 받는 프로그램은 어떤 방식으로든 해당 입력을 구문 분석하도록 설계되었습니다. 데이터를 파이프하면 readlink텍스트 스트림을 수신하지만 내용이 아닌 파일만 처리하기 때문에 어떻게 해야 할지 모릅니다. ls또는 cd와 같은 프로그램도 마찬가지입니다 cp. 텍스트/데이터 스트림을 처리하는 프로그램만 파이프의 입력을 받아들일 수 있습니다.

답변2

프로그램이 stdin명령줄 인수에서 입력을 받거나 명령줄 인수로 입력을 받는지는 디자이너에게 달려 있습니다. 두 가지 방법 모두 장점이 있습니다. 그러나 파일을 엄격하게 조작하는 프로그램의 경우 파일 이름을 명령줄 인수로 전달하는 것이 일반적으로 stdin.

가장 분명한 이유는 파일에서 프로그램을 실행하는 일반적인 경우에는 . readlink file대신 : 을 입력하는 것이 더 쉽다는 것입니다 echo file | readlink.

더 미묘한 문제는 정확성입니다. 문제는 파일 이름이 를 통해 전달될 때 stdin프로그램이 하나의 파일 이름을 다른 파일 이름과 구별할 수 있어야 한다는 것입니다. 일반적으로 이는 파일 이름이 공백이나 개행 문자로 구분되어 있다고 가정하여 수행되지만 파일 이름에 공백이 포함될 수 있으므로 이는 올바르지 않습니다. 더 나은 접근 방식은 null 바이트를 사용하여 파일 이름을 구분하는 것이지만, null 바이트로 구분된 파일 목록을 생성하는 것은 불편할 수 있습니다.

명령줄에 파일 이름을 전달하면 쉘이 프로그램의 모든 구문 분석 및 참조를 처리하므로 이 문제를 피할 수 있습니다. 이를 입력하면 touch $'foo\nbar'특별한 touch구문 분석이나 인용 자체를 처리할 필요 없이 개행 문자가 포함된 파일 이름으로 올바르게 처리됩니다.

즉, stdin특정 프로그램에 대한 파일을 전달하려는 경우 그렇게 할 수 있습니다. 그것이 xargs목적입니다. xargs명령줄의 인수만 받아들이고 이를 통과시키는 프로그램을 사용할 수 있습니다 stdin.

즉, 다음을 수행할 수 있습니다 which my_script | xargs readlink.

항상 이런 방식으로 작업하려면 readlink별칭을 만들 수 있습니다 alias readlink="xargs readlink". 이렇게 하면 원래 원했던 방식으로 들어갈 수 있습니다 which my_script | readlink.

답변3

STDIN을 통해 인수를 가져오지 않는 명령의 경우 다음 코드 pragma를 사용할 수 있습니다.

$ readlink $(which my_script_link)

$ ln -s /bin/ls ~/bin/somecmd

이제 거기에 있는지 확인하십시오 $PATH.

$ which somecmd
~/bin/somecmd

또는 선호하는 방법은 type다음을 대신 사용하는 것입니다 which.

$ type somecmd
somecmd is /home/saml/bin/somecmd

아니면 그냥 값:

$ type -P somecmd 
/home/saml/bin/somecmd

이제 다음을 실행합니다 readlink.

$ readlink $(type -P somecmd)
/bin/ls

관련 정보