Reputation: 19879
I want to create a simple regular expression to match some files. The command npm ls --dev --parseable
prints out a bunch of files, for example:
/Users/chetcorcos/code/dev-tool/node_modules/fsevents/node_modules/tough-cookie
/Users/chetcorcos/code/dev-tool/node_modules/fsevents/node_modules/tunnel-agent
/Users/chetcorcos/code/dev-tool/node_modules/fsevents/node_modules/rimraf
/Users/chetcorcos/code/dev-tool/node_modules/fsevents/node_modules/rimraf/node_modules/glob
/Users/chetcorcos/code/dev-tool/node_modules/fsevents/node_modules/rimraf/node_modules/glob/node_modules/inflight
/Users/chetcorcos/code/dev-tool/node_modules/fsevents/node_modules/rimraf/node_modules/glob/node_modules/inflight/node_modules/wrappy
I want to get back a string that looks something like this:
tough-cookie|tunnel-agent|rimraf|inflight|wrappy
To get this, I want to "split by newline, map over basename, and join with a pipe". In JavaScript with Ramdajs, I'd so something like this:
R.pipe(R.split('\n'), R.map(R.split('/')), R.map(R.nth(-1)), R.join('|'))
Any ideas how to do something like this in bash? Whats the idiomatic way of doing this?
Upvotes: 3
Views: 1753
Reputation: 11
You already have a 'list' of strings, separated by '\n'.
Just map basename
on each item (using xargs) - then you'll get list of basenames separated by '\n' plus final '\n'. Then replace each '\n' with '|' symbol:
anycmd | xargs -r -n1 basename | tr '\n' '|'
You may then remove last '|' by either sed or second xargs.
anycmd | xargs -r -n1 basename | tr '\n' '|' | sed 's/|$//'
or
anycmd | xargs -r -n1 basename | xargs | tr ' ' '|'
Upvotes: 1
Reputation: 295629
Bash doesn't have functional programming primitives built in. It's possible to build them with a hundred lines of code or so, but also not particularly worth it for this kind of use case.
Consider:
content=$(npm ls --dev --parseable | sed -e 's@.*/@@' | paste -s -d '|')
echo "$content"
...this routes the stdout of NPM into sed
, telling it to replace everything up to the last slash in each line with an empty string, and then routing the stdout of sed
into paste
, using that to combine all lines into a single string with |
separating them.
Alternately, to use no tools not built into bash itself (other than your data source, npm
):
#!/bin/bash
# note that this requires bash 4.0 or later
mapfile -t lines < <(npm ls --dev --parseable) # read content into array
lines=( "${lines[@]##*/}" ) # trim everything prior to last / in each
(IFS='|'; printf '%s\n' "${lines[*]}") # emit array as a single string with |s
Upvotes: 4
Reputation: 50200
You could just pipe that thing to awk
and have awk
pick off the last element:
npm ls --dev --parseable | awk -F"/" '{output=output$(NF)"|"} END { sub(/[|]+$/, "", output); print output }'
That awk
script will split incoming records by /
, capture the last element $(NF)
to variable output
with a pipe to delimit, Then once complete, will strip the last pipe using gsub
and spit the results out
Upvotes: 1