¿Por qué algunos progtwigs (como el readlink) no pueden recibir información de un tubo?

Tengo un enlace simbólico a un script en mi $PATH cuyo file quería editar. Olvidé el file, así que traté de hacer lo siguiente:

 $ which my_script_link | readlink 

Esperaba que saliera el filepath, pero en su lugar salía

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

He visto un comportamiento similar anteriormente en otras situaciones (como tratar de canalizar una list de files en vim para su edición). Sé que hay soluciones, como un subshell readlink $(which my_script_link) , pero quiero entender por qué las tuberías no funcionan como creo que deberían hacerlo en esta situación.

¡Gracias!

En pocas palabras, porque el progtwig no está escrito para hacerlo. Depende de los progtwigdores decidir si su software puede leer de STDIN o si requiere un file de input. En el caso de readlink , su página de man dice (el énfasis es mío):

readlink – imprime enlaces simbólicos resueltos o nombres de files canónicos

SINOPSIS
readlink [OPTION] … ARCHIVO

Como regla general, los progtwigs que toman input de STDIN están diseñados para analizar de alguna manera esa input. Cuando canaliza datos a readlink , recibe una secuencia de text y no tiene idea de qué hacer con ella, ya que solo trata con los files y no con sus contenidos. Lo mismo es cierto para progtwigs como ls o cd o cp etc. Solo los progtwigs que se ocupan de secuencias de text / datos pueden aceptar inputs de un conducto.

Si el progtwig toma su input de stdin o como arguments de línea de command, depende del diseñador. Ambos enfoques tienen sus méritos. Sin embargo, para los progtwigs que operan estrictamente en files, generalmente es más conveniente pasar los nombres de file como arguments de command-line en lugar de a través de stdin .

La razón más obvia es que el caso común, el de simplemente ejecutar un progtwig en un file, es más fácil de escribir: readlink file lugar de echo file | readlink echo file | readlink .

Un problema más sutil es la corrección. El problema es que cuando los nombres de file se pasan a través de stdin , el progtwig necesita poder distinguir un nombre de file de otro. A menudo, esto se hace suponiendo que los nombres de los files están separados por espacios en blanco o líneas nuevas, pero esto es incorrecto ya que los nombres de file pueden include espacios en blanco. Una forma mejor es separar los nombres de file con bytes nulos, pero puede ser inconveniente generar una list de files separados por nulos.

Al pasar nombres de files en la command-line se evita este problema porque el shell maneja todo el análisis sintáctico y las comillas para el progtwig. Puede escribir touch $'foo\nbar' y touch correctamente lo ve como un nombre de file que contiene una nueva línea, sin tener que manejar ningún análisis especial o citar a sí mismo.

Dicho todo esto, si desea pasar files a través de stdin para un progtwig en particular, puede hacerlo. Esto es para lo que es xargs . xargs permite tomar un progtwig que solo acepta arguments en la línea de command y, en su lugar, hacer que tome sus arguments a través de stdin .

En otras palabras, te permite hacer esto: which my_script | xargs readlink which my_script | xargs readlink .

Si desea hacer que readlink funcione siempre de esta manera, podría crear un alias: alias readlink="xargs readlink" . Eso te permitiría escribir which my_script | readlink which my_script | readlink , como originalmente quisiste

Para los commands que no toman arguments a través de STDIN, puede usar este código pragma en su lugar:

 $ readlink $(which my_script_link) 

Ejemplo

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

Ahora comtesting que esté en $PATH .

 $ which somecmd ~/bin/somecmd 

O la forma preferida, utilizando el type instad del which :

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

O solo el valor:

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

Ahora ejecutamos readlink :

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