2

I have multiple files with different job names. The job name is specified as follows.

#SBATCH --job-name=01_job1 #Set the job name

I want to use sed/awk/grep to automatically get the name, that is to say, what follows '--job-name=' and precedes the comment '#Set the job name'. For the example above, I want to get 01_job1. The job name could be longer for several files, and there are multiple = signs in following lines in the file.

I have tried using grep -oP "job-name=\s+\K\w+" file and get an empty output. I suspect that this doesn't work because there is no space between 'name=' and '01_job1', so they must be understood as a single word.

I also unsuccessfully tried using awk '{for (I=1;I<NF;I++) if ($I == "name=") print $(I+1)}' file, attempting to find the characters after 'name='.

Lastly, I also unsuccessfully tried sed -e 's/name=\(.*\)#Set/\1/' file to find the characters between 'name=' and the beginning of the comment '#Set'. I receive the whole file as my output when I attempt this.

I appreciate any guidance. Thank you!!

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
user19619903
  • 131
  • 5

5 Answers5

2

Use this, you was close, just correctness of your grep -oP attempt (the main issue if you are trying to match a space after = character):

$ grep -oP -- '--job-name=\K\S+' file
01_job1

The regular expression matches as follows:

Node Explanation
job-name= 'job-name='
\K resets the start of the match (what is Kept) as a shorter alternative to using a look-behind assertion: perlmonks look arounds and Support of K in regex
\S+ non-whitespace (all but \n, \r, \t, \f, and " ") (1 or more times (matching the most amount possible))
Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
2

You need to match the whole string with sed and capture just what you need to get, and use -n option with the p flag:

sed -n 's/.*name=\([^[:space:]]*\).*/\1/p'

See the online demo:

#!/bin/bash
s='#SBATCH --job-name=01_job1           #Set the job name'
sed -n 's/.*name=\([^[:space:]]*\).*/\1/p' <<< "$s"
# => 01_job1

Details:

  • -n - suppresses default line output
  • .* - any text
  • name= - a literal name= string
  • \([^[:space:]]*\) - Group 1 (\1): any zero or more chars other than whitespace
  • .* - any text
  • p - print the result of the successful substitution.
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • With `awk`, you [could probably use](https://ideone.com/qftmp6) `awk '$2 ~ /^--job-name=/ {gsub(/.*=/, "", $2); print $2}'`, but that depends on assumptions already. – Wiktor Stribiżew Jan 05 '23 at 14:16
2

Simlar to the answer of Gilles Quenot

grep -oP -- '--job-name=\K.*(?= *# *Set the job name)'

This adds a look-ahead to ensure that the string is followed by #Set the job name

kvantour
  • 25,269
  • 4
  • 47
  • 72
2

1st solution: In GNU awk with your shown samples please try following awk code.

awk -v RS=' --job-name=\\S+' 'RT && split(RT,arr,"="){print arr[2]}' Input_file

OR a non-one liner form of above GNU awk code would be:

awk -v RS=' --job-name=\\S+' '
RT && split(RT,arr,"="){
   print arr[2]
}
' Input_file

2nd solution: Using any awk please try following code.

awk -F'[[:space:]]+|--job-name=' '{print $3}' Input_file

3rd solution: Using GNU grep please try following code with your shown samples and using non-greedy .*? approach here in regex.

grep -oP '^.*?--job-name=\K\S+' Input_file
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
1

You can use a lookbehind and lookahead with GNU grep to get exactly what you describe:

grep -oP '(?<=--job-name=)\S+(?=\s+#Set the job name)' file

Or with awk:

awk '/^#SBATCH[[:space:]]+--job-name=/ && 
     /#Set the job name$/ {
        sub(/^[^=]*=/,"")   
        sub(/#[^#]*$/,"")   
        print
     }' file 

Or perl:

perl -lnE 'say $1 if /(?<=--job-name=)(\S+)(?=\s+#Set the job name)/'   file    

Any prints:

01_job1
dawg
  • 98,345
  • 23
  • 131
  • 206