1

In the SED command, I want to remove everything that comes after 2000_SOMENAME also if possible want to give an error if that format is not found.

For example, if the file name is ITALY_2022_BEST1FRIENDS2_ROME.txt . I only want 2022_BEST1FRIENDS2 if that pattern is not found I want to give an error in the shell script.

username=$(find . -iname '*.txt' | sed -e 's/.*_\([0-9]\{4\}_[0-9|A-z]*\).*/\1/i' | sort - | uniq -ui |tr -d '\n')

The previous question and more info here: Extracting a partial part from filename using SED Thank you!!

1 Answer 1

1

In this particular case, it probably makes more sense to use grep -o rather than sed, because grep will exit with an error if it finds no results. (The -o makes it only return the matched portion and not the whole line.)

The tricky thing is that you're piping to other commands, and you want to preserve that exit status in the case of an error.

If using bash, you could get the pipe to fail if any component fails with set -o pipefail (set it back with set +o pipefail afterwards to reset it if you want).

There may be similar methods for other shells.

set -o pipefail
username="$(find . -iname '*.txt' | grep -o -i '[0-9]\{4\}_[0-9A-Z]*' | sort - | uniq -ui |tr -d '\n')"
# get the exit status of the previous command
pipeexit="$?"
set +o pipefail
if [[ "$pipeexit" != 0 ]] ; then
    echo "username not found" >&2
    # line below quits the script; remove if you don't want that
    exit "$pipeexit"
fi

I followed your lead in making the pattern case insensitive (-i to grep; you had i in your sed command), and left the rest of the commands in the pipe unmodified: I assume you had a reason for them. (Though the tr command seems suspect; why mash all the results together on one line?)

You might also consider a simpler method to check for an "error": just checking if the $username variable is empty, which it would be if there were no grep results (but of course also if no .txt files were found by find, etc.; not sure if you wanted that ...).

username="$(find . -iname '*.txt' | grep -o -i '[0-9]\{4\}_[0-9A-Z]*' | sort - | uniq -ui |tr -d '\n')"
if [ -z "$username" ] ; then
    echo "username not found" >&2
    exit "$pipeexit"
fi

Which would work in other shells most likely...

8
  • But the issue I keep having is if there is say a year that is greater than 4 characters due to user input error it should be invalid. Only take an answer when it is XXXX_ANYCHARACTER - where the XXXX represents any number. Jun 15 at 0:33
  • 1
    How do you want to guard against that? Should the character right before the pattern need to be _? username="$(find . -iname '*.txt' |grep -o -i '_[0-9]\{4\}_[0-9A-Z]*' | sed 's/^_//' | sort - | uniq -ui |tr -d '\n' )"
    – frabjous
    Jun 15 at 1:13
  • Thanks a lot, @frabjous. That is exactly what I was looking to do. I will try to implement this into my bigger code and see if it works. In my sample script, it does exactly what I wanted. Could you explain the sed '^_//' part? and the -i in the grep checks for case sensitivity? Jun 15 at 2:03
  • 1
    Yes the -i is for case insensitivity; I only put that in because you had i at the end of your sed substitution in the original; take it out if you don't want it. The new grep pattern starts with _ and so _ is at the start of the results, but if I understand you right, you don't want the starting _ in the results, so sed s/^_// just removes them.
    – frabjous
    Jun 15 at 4:46
  • 1
    Sorry, I'm having a really hard time understanding what you're asking. Do you mean that instead of starting from a file ITALY_2022_BEST1FRIENDS2_ROME.txt listed by find . -iname '*.txt', you'd have a folder named ITALY_2022_BEST1FRIENDS2_ROME/' or something like that and want to extract the same part from it? Just change the find command appropriately, e.g., find . -type d maybe? Not sure because your question is very unclear.
    – frabjous
    Jun 16 at 15:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.