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텍스트 스트림을 수신하고 내용이 아닌 파일만 다루기 때문에 어떻게 해야할지 전혀 모릅니다. lsor cd등 의 프로그램에서도 마찬가지입니다. cp텍스트/데이터 스트림을 처리하는 프로그램만 파이프의 입력을 받아들일 수 있습니다.

답변2

프로그램이 입력을 명령줄 인수로 가져오거나 stdin명령줄 인수로 가져오는지는 디자이너에게 달려 있습니다. 두 가지 접근 방식 모두 장점이 있습니다. 그러나 파일에 대해 엄격하게 작동하는 프로그램의 경우 일반적으로 stdin.

가장 분명한 이유는 파일에서 프로그램을 실행하는 일반적인 경우 readlink fileecho 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

관련 정보