which(1)
Почитавши про бурю ув склянці з утілітою which(1) ув деб'яні, пограв сам з собою ув code golf: на якій мові вийде написати найкоротший аналог which(1), який
їсть декілька агрументів, e.g.
my-which ls BOGUS catмає зупинитися після 1го неіснуючого виконуваного файлу та повернути, у такому разі, exit code > 0.
Найкрихітніший результат вийшов, як завжди, на GNU Make:
#!/usr/bin/make -f
f = $(firstword $(wildcard $(addsuffix /$1,$(subst :, ,$(PATH)))))
%:;@echo $(or $(call f,$@),$(error $@ not found in PATH))Працює так:
$ ./which.mk ls BOGUS cat
/usr/bin/ls
which.mk:3: *** BOGUS not found in PATH. Stop.
$ echo $?
2На 2му місці Рубі:
#!/usr/bin/env ruby
def f e; (ENV['PATH'] || '').split(?:).filter{|d| File.executable?(d+'/'+e)}.map{|d| d+'/'+e}[0]; end
ARGV.each {|i| puts(f(i) || abort("#{$0}: #{i} not found in PATH")) }Дуже посередній результат на sh:
#!/bin/sh
f() {
IFS=':'
for p in $PATH; do
[ -x "$p/$1" ] && { echo "$p/$1"; return; }
done
return 1
}
for i in "$@"; do
f "$i" || { echo "$0: $i not found in PATH" 1>&2; exit 1; }
doneА найогиднійший, як завжди, на ноуді (v17.0.1):
#!/usr/bin/env node
let {access} = require('fs/promises')
let afilter = async (arr, predicate) => { // та за шо
return (await Promise.allSettled(arr.map(predicate)))
.filter( v => v.status === 'fulfilled').map( v => v.value)
}
let f = e => afilter((process.env.PATH || '').split(':'), async p => {
await access(p+'/'+e, 1)
return p+'/'+e
})
async function main() {
let args = process.argv.slice(2).map( async p => {
return {exe: p, location: await f(p)}
})
for await (let r of args) {
if (!r.location.length) {
console.error(`${process.argv[1]}: ${r.exe} not found in PATH`)
process.exitCode = 1
break
}
console.log(r.location[0])
}
}
main()Можна було 1 в 1 скопіювати версію на рубі, але я хотів уникнути ⓐ
try/catch (fs.accessSync() кидає іксепшона) та ⓑ process.exit().
Upd: не витримав, переписав останній приклад традиційними колбеками, стилем також відомим як як діди:
#!/usr/bin/env node
let fs = require('fs')
let f = (ok, error) => {
let dirs = (process.env.PATH || '').split(':')
return function dive(e) {
let dir = dirs.shift() || error(e); if (!dir) return
let file = dir+'/'+e
fs.access(file, fs.constants.X_OK, err => err ? dive(e) : ok(file))
}
}
let args = process.argv.slice(2)
let main = exe => exe && f( e => (console.log(e), main(args.shift())), e => {
console.error(`${process.argv[1]}: ${e} not found in PATH`)
process.exitCode = 1
})(exe)
main(args.shift())
Чудовими _ = _ => _ && _( _ => (_, _), _ => { ... })(_) не насолоджуватися неможливо.

no subject
Сколько нового узнал! Дякую!!! (
command -v- never heard before!)no subject
бггг
немає за що
no subject
no subject
you're welcome!
no subject
#!/usr/bin/env node const fs = require('fs') const dirs = (process.env.PATH || '').split(':') const f = (e, cont) => dirs.map(d => d + '/' + e) .reduce((p, d) => g => p(f => f ? g(f): fs.access(d, fs.constants.X_OK, err => g(!err && d))), f => f())(f => f ? (console.log(f), cont()): (console.log(`${process.argv[1]}: ${e} not found in PATH`), process.exitCode = 1, cont())) process.argv.slice(2).reduce((p, c) => g => p(_ => f(c, g)), f => f())(_ => _)no subject
о, порядок
але, на жаль, не зовсім працює згідно спеціфікації:
воно повинно закінчити роботу після
BOGUS not found in PATHі НЕ друкувати/usr/bin/catno subject
no subject