1

I have a URL:

www.google.com/word/word1/word_2/word3/word4

I would like to use awk to print only the words that contain the _ special character. Sometimes the folder hierarchy may change:

www.google.com/word/word1/word2/word3/word_4

I was using this, but sometimes the folders are above $6:

folder=$(echo "$url" | awk -F/ '{print $6}')

I need to print the folder name between the / characters.

3 Answers 3

3

Something like this works ... there may be more efficient approaches:

echo 'www.google.com/word/word1/word2/word3/word_4' | awk -F'/' '{for(i=2;i<=NF;i++){if($i~/_/){print $i}}}'
word_4

We just iterate over all fields and check if the word contains an underscore; if yes, print the word. Starting at two, assuming that the domain name doesn't change.

Thought of a non-iterative approach:

$ echo 'www.google.com/word/word1/word_2/word3/word4' | awk '{print gensub(/^.*\/([^/]+_[^/]*).*/,"\\1","1")}'
word_2

If it doesn't need to be awk - here a somewhat more elegant solution:

$ echo 'www.google.com/word/word1/word_2/word3/word4' | grep -oE '[^/]+_[^/]*'
word_2
1
  • May be worth noting that gensub() and -o are non-standard GNU extensions. Commented May 28, 2023 at 19:39
2

A simple solution would be just:

% echo 'www.google.com/word/word1/word_2/word3/word4' | tr -s '/' '\n'  |grep _
word_2

That is, change slashes to newlines, then print the resulting lines that contain an underscore.

If something other than the slash should also be considered a word separator, include them in the first quoted string. Or do it the other way around and list anything that can be part of a word:

% echo 'www.google.com/word/word1/word_2/word3/word4' | tr -sc 'a-zA-Z_0-9' '\n'  |grep _
word_2
4
  • Or if it's in a variable as per the Q, in some shells including bash as tagged: echo "${url/\//$'\n'}" | grep _ . But since the Q asks to not check the first token -- which as a hostname shouldn't contain _ but some do -- | tail +2 | grep _ or | sed '1d;/_/!d'. Or with one (portable) awk echo "$url" | awk -v RS=/ 'NR>1&&/_/' Commented May 27, 2023 at 23:51
  • @dave_thompson_085, well, idk, it says "print only the words that contain the _", without further specifying that some of them should be ignored (but then it doesn't exactly define "word" either)
    – ilkkachu
    Commented May 28, 2023 at 10:36
  • The example in the Q has a hostname that is not a word by the usual definition (\w+) and does not say 'word', followed by multiple tokens that are words and do say 'word'. I thought that was clear enough. Commented May 29, 2023 at 0:28
  • @dave_thompson_085, I don't know if they agree on that usual definition of a word. Something like six-pack could also be reasonably considered a word.
    – ilkkachu
    Commented May 29, 2023 at 7:01
2

If using zsh instead of bash, you could extract the /-separated words that contain _ with:

words=( ${(M)${(s[/])url}:#*_*} )

That would work regardless of what byte values those words might contain and doesn't involve forking a process or running an external utility.

${(s[/])url} splits the variable on /. ${(M)array:#pattern} expands to the elements of the array that Match the pattern.

I can also be done in bash, but it's more cumbersome:

words=()
IFS=/; set -o noglob
for word in $url; do
  if [[ $word = *_* ]]; then
    words+=( "$word" )
  done
done

awk / perl would be more appropriate if you have a long list of URLs, one per line coming from some text stream / file.

With perl:

that-stream | perl -F/ -lae 'print for grep /_/, @F'

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .