I'm trying this, but I'm clearly doing something wrong beyond my comprehension :(
sv () { ls -la ~/releases | grep -i $1 | perl -l -ne "/($1.*$)/ && print $1"; }
I'm getting this:
$ sv blah
drwxr-xr-x 10 bob staff 320B Dec 30 07:12 blah-1.2.3
but I would like this:
$ sv blah
blah-1.2.3
CodePudding user response:
Using shell expansion on wildcard *
touch blah-1.2.3
mkdir ~/releases
sv() ( shopt -s nullglob; for file; do ls -d "$file"*; done )
sv bla ~/relea
Output
blah-1.2.3
/home/me/releases/
DO NOT USE ls' output for anything. ls
is a tool for interactively looking at directory metadata. Any attempts at parsing ls
output with code are broken. Globs are much more simple AND correct: for file in *.txt
. Read http://mywiki.wooledge.org/ParsingLs
CodePudding user response:
The problems are do to code injection bugs, both into the Perl program, and into the regex literal.
See How can I process options using Perl in -n or -p mode? for ways to avoid generating Perl code from the shell.
id="$1" perl -nle'/(?:^|\/)\Q$ENV{id}/ && print $ENV{id}'
perl -snle'/^(?:^|\/)\Q$id/ && print $id' -- -id="$1"
But there are better approaches. See the other answer(s).
CodePudding user response:
If OP insists on parsing the ls
output ...
$ sv () { 'ls' -la ~/releases | awk -v str="$1" 'tolower($(NF))~tolower(str) {print $(NF)}'; }
bah-1.2.3
NOTES:
'ls'
to disable use of any aliasestolower()
- wrapper for both sides of~
to facilitate a case-insensitive match$(NF)~str
- if last field ($(NF)
) contains the stringstr
then ...print $(NF)
- print the last field ($(NF)
)- will not work correctly for files that contain white space
CodePudding user response:
One idea using find
, xargs
and basename
:
sv () { find ~/releases -iname "*$1*" -print0 | xargs -0 -r basename -a; }
Taking for a test drive:
$ sv blah
blah-1.2.3
NOTES:
find / -iname
- for case insensitive matching- the
find / -print0
andxargs / -0
options are included to address names with special characters (eg, linefeeds) in the name basename -a
- apply basename to multiple names (eg,find
passes multiple matches toxargs
); alternatively:xargs -n1 -r basename
to supply a single match at a time tobasename
- this will also search any subdirectories of
~/releases
; this can be modified withfind
options-maxdepth
and-mindepth
as needed - this will match on anything with
blah
in the name ... files, directories, symlinks, etc; this can be modified withfind
tests like-type