Can I select only one result from a bash glob?
Solution 1
The following works in bash 4.2:
list=( /<root_path>/<process_two_path>/logs/* )
echo "${list[-1]}"
If your bash is an older version:
list=( /<root_path>/<process_two_path>/logs/* )
echo "${list[${#list[@]}-1]}"
Solution 2
POSIXly:
set -- /<root_path>/<process_two_path>/logs/*
shift "$(($# - 1))"
printf '%s\n' "$1"
Since you mention zsh
:
print -r /<root_path>/<process_two_path>/logs/*([-1])
Solution 3
Use the bash glob in a bash for loop. Like this:
for filename in <logdir>/*; do :; done; echo "$filename"
This depends on the fact that bash does glob expansion sorted alphabetically. Read the bash manual for more information. Note that this depends on LC_COLLATE. This also depends on the fact that the variable filename
still contains the last value after the loop has terminated.
If you want the filename with the oldest timestamp you can do it like this:
for filename in <logdir>/*; do echo "$filename"; break; done
Solution 4
-1 is the default in pipelines, and ls output should already be sorted:
ls | tail -n1
If others were looking for how to insert the first or last result interactively, you can bind menu-complete or menu-complete-backward in .inputrc:
"\e\t": menu-complete
"\e[Z": menu-complete-backward # shift-tab
If show-all-if-ambiguous is enabled, set completion-query-items 0
removes the prompt when there are 101 or more results and set page-completions off
disables the pager.
AncientSwordRage
I'm just this guy, y'know? (he/him) Secret ninja-muslim programmer, roleplayer and all-round nuisance. Desh by marriage. I have approximate knowledge of many things Cat thumb-servant. I moderate Sci-fi StackExchange, but I'm active on RPG.se, Puzzling.se and I dabble on the writing and worldbuilding StackExchanges. Sci-Fi I used to be the secretary of my university Sci-fi and fantasy club and I love everything from Horror to 'Saturday morning cartoons'. I help moderate this stack (with a diamond), and I'm active/interested in the marvel, back-to-the-future, star-wars and ghostbusters tags. Happy to meet and greet new users, as well as point people in the right direction for story-id questions. RPG TO BE FILLED StackOverflow TO BE FILLED
Updated on September 18, 2022Comments
-
AncientSwordRage almost 2 years
I'm trying to write a script for work to automate some reporting on an output. The Log files are (currently, it's being 'standardise' in the future) stored in this sort of path structure:
/<root_path>/<process_one_path>/logs/<time_date_stamp>/<specific_log_file>
/<root_path>/<process_two_path>/logs/<different_time_date_stamp>/<specific_log_file>
Every part of the path is known except the time date stamps, which are always the latest in the folder.
If I try to use a wild card in place of the time date stamp, I get multiple results, e.g.:
> ls /<root_path>/<process_two_path>/logs/* [tab] 20130102-175103 20130118-090859 20130305-213506
I only want it to return the latest one, is this possible with Bash?
NB (I don't have zsh, and as lovely as it sounds I doubt we'll ever get it at work)
-
AncientSwordRage about 11 yearsThis definitely works on my home computer but I can't guarantee it'll work at work?
-
phemmer about 11 years@Pureferret the part that might not work is the negative array index (
-1
). This was added in bash 4.2. RHEL5 is probably the oldest supported mainstream enterprise distro available and it uses bash 4.2.20. -
Stéphane Chazelas about 11 yearsOlder versions of
bash
have:"${list[@]: -1}"
like inksh93
([-1]
comes fromzsh
). -
jordanm about 11 years@Patrick - RHEL5 uses bash
3.2
. RHEL 3 and 4 still supported under extended life. -
phemmer about 11 years@StephaneChazelas That doesn't work when I try it.
-
Stéphane Chazelas about 11 years@Patrick, what have you tried. That syntax exists as far back as bash 2.0.3 (15 years ago) at least. Note that you need the space before "-1" to disambiguate from the
${var:-default}
syntax, -
Gilles 'SO- stop being evil' about 11 years@Pureferret You can also do arithmetic with the array length, see my edit.
-
Stéphane Chazelas about 11 years@Gilles, inside
[...]
arithmetic expansion is already on so you don't need the$((...))
.${#list}
is correct inzsh
but not inksh93
orbash
where you need${#list[@]}
-
Gilles 'SO- stop being evil' about 11 years@StephaneChazelas Oops, thanks for the reminder, I always get bitten by that one.
-
rahmu about 11 yearsNote that you shouldn't parse the output of
ls
. Ever. -
pyropunk51 about 11 yearsWhy is that? And how does it differ from using the output from a glob?
-
pyropunk51 about 11 yearsmywiki.wooledge.org/ParsingLs explains it...
-
woky over 7 yearsIs it possible to do it inline? That is without intermediate $list variable.
-
phemmer over 7 years@woky I can't think of a way. You could use
echo /foo/* | awk '{ print $1 }'
, but that's pretty dirty, and error prone (spaces break it, etc). You could probably do it inzsh
though. -
Gavin S. Yancey almost 4 yearsParsing
ls
is generally a bad idea -- filenames can contain all sorts of weird characters, including anythingls
is able to use as a separator.