1

I am new to bash shell scripting and would be thankful for suggestions of a script that can do this task. I have a file (list.cqt) with many lines. Each line has a list of fields separated by '/' in the following format: /Field1/Field2/Field3/Field4/Field5/Field6/Field7/Field8/Field9/Field10

For e.g. the contents in list.cqt are:
/F11/F12/F13/F14/F15/F16/F17/F18/F19/F110
/F21/F22/F23/F24/F25/F26/F27/F28/F29/F210
...
/Fx1/Fx2/Fx3/Fx4/Fx5/Fx6/Fx7/Fx8/Fx9/Fx10

(I modifyied the names inside each field just for simplifying the problem. Only the number of fields is constant in each line. Contents in each field can be anything - numbers, characters, etc)

I need to write a script to execute the following command by reading each line from list.cqt:
command arg1 arg2 arg3 arg4 *arg5* arg6 arg7 arg8 arg9 arg10

Only arg4, arg5, arg7 and arg10 change for each line read. Rest all remain the same.
arg4 is Field4 in that line in list.cqt
arg5 is Field6 in that line in list.cqt
arg7 basically starts with -1000 for the first command and changes in increments of 100. So for the second command it will be -900 for second command, so on, and 0 for 11th command, 100 for 12th command, 200 for 13th command etc.
arg10 is same absolute value as arg7 but with opposite sign. So if arg7 is -600, arg10 is 600. If arg7 is 400, arg10 is -400.

For example, reading the first two lines from list.cqt in the above example of the file, the commands will be:
command arg1 arg2 arg3 F14 F16 arg6 -1000 arg8 arg9 1000
command arg1 arg2 arg3 F24 F26 arg6 -900 arg8 arg9 900

Thank you!

0

2 Answers 2

3

You can control the delimiter of the shell's read command via the Internal Field Separator IFS. If you read into an array it's easy to access the indexed values. Then it becomes a simple matter of looping over the input and updating your counter variables. If you save the arguments to an array, you can just pass the expanded array as the arguments to your command.

#!/bin/bash

# Use set -x to see if the array "args" is getting assigned the values you expect.
IFS='/'
counter=-1000
while read -a fields; do
    (( counter+=100 ))
    args=(
        'arg1' 'arg2' 'arg3'
        "${fields[4]}" "${fields[6]}" 'arg6'
        $counter 'arg8' 'arg9' $(( -1 * counter ))
    )
    # command "${args[@]}"
done < list.cqt
Sign up to request clarification or add additional context in comments.

2 Comments

I don't really think it's necessary to create an array (args), just put the arguments after command. It's not really a good idea to increment the counter as a side effect. An explicit, separate increment statement is better practice for readability and maintainability.
@DennisWilliamson you have a point about the counter (edited); however, putting the arguments into an array allows you to write it on multiple lines without backslash-escaping newlines, which is a risky practice.
2

I added echo before command because it's better to check if generated list is correct:

arg7=-1000
arg10=1000
while read line
do
  set $(echo $line | tr / ' ')
  echo command arg1 arg2 arg3 "$4" "$6" arg6 "$arg7" arg8 arg9 "$arg10"
  arg10=$((arg10-100))
  arg7=$((arg7+100))
done < list.cqt

If it is, just remove echo and run the script.

Here you process list.cqt line by line and set parts of its line to positional arguments of shell; then you use this parts as $4 and $6. Variables arg10 and arg7 are increased/decreased each time a line from the list.cqt file is processed.

Update

You can also use arrays instead of positional arguments (thanks to Dennis Williamson and kojiro for the tip):

arg7=-1000
arg10=1000
while IFS=/ read line
do
  echo command arg1 arg2 arg3 "${line[4]}" "${line[6]}" arg6 "$arg7" arg8 arg9 "$arg10"
  arg10=$((arg10-100))
  arg7=$((arg7+100))
done < list.cqt

That makes the code a little bit faster and cleaner.

5 Comments

$[] is deprecated, use $(()) (e.g. (( arg10 -= 100 )) or arg10=$((arg10 - 100))). No need for cat, use done < list.cqt (this also avoids creating a subshell so variable values are available after the loop exits. Use while IFS=/ read -r line instead of tr.
Dennis, thank you for real good tips. The only thing, I didn't catch the idea, how could IFS help us?
Here's evidence that $[] syntax was deprecated long ago. Regarding IFS, please see my answer.
@kojiro: thank you very much; you mean I could use array instead of set + positional arguments. That is a very good idea. Thank you once again.
I know it's not hip to say I like reputation points, but I like reputation points. </hint>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.