简体   繁体   中英

Passing input to sed, and sed info to a string

I have a list of files (~1000) and there is 1 file per line in my text file named: 'files.txt'

I have a macro that looks something like the following:

#!/bin/sh
b=$(sed '${1}q;d' files.txt)

cat > MyMacro_${1}.C << +EOF

myFile = new TFile("/MYPATHNAME/$b");

+EOF

and I use this input script by doing

./MakeMacro.sh 1

and later I want to do

./MakeMacro.sh 2
./MakeMacro.sh 3

...etc

So that it reads the n'th line of my files.txt and feeds that string to my created .C macro.

If I am understanding you correctly, you can do a for loop in bash to call the script multiple times with different arguments.

for i in `seq 1 n`; do ./MakeMacro.sh $i; done

Based on the OP's comment, it seems that he wants to submit the generated files to Condor. You can modify the loop above to include the condor submission.

for i in `seq 1 n`; do ./MakeMacro.sh $i; condor_submit <OutputFile> ; done
i=0
while read file
do
    ((i++))
    cat > MyMacro_${i}.C <<-'EOF'

    myFile = new TFile("$file");

    EOF
done < files.txt

Beware: you need tab indents on the EOF line.

I'm puzzled about why this is the way you want to do the job. You could have your C++ code read files.txt at runtime and it would likely be more efficient in most ways.

If you want to get the Nth line of files.txt into MyMacro_N.C , then:

{
echo
sed -n -e "${1}{s/.*/myFile = new TFILE(\"&\");/p;q;}" files.txt
echo
} > MyMacro_${1}.C

So that it reads the n'th line of my files.txt and feeds that string to my created .C macro.

Given this statement and your tags, I'm going to answer using shell tools and not really address the issue of the .c macro.

The first line of your script contains a sed script. There are numerous ways to get the Nth line from a text file. The simplest might be to use head and tail .

$ head -n "${i}" files.txt | tail -n 1

This takes the first $i lines of files.txt , and shows you the last 1 lines of that set.

$ sed -ne "${i}p" files.txt

This use of sed uses -n to avoid printing by default, then prints the $i th line. For better performance, try:

$ sed -ne "${i}{p;q;}" files.txt

This does the same, but quits after printing the line, so that sed doesn't bother traversing the rest of the file.

$ awk -v i="$i" 'NR==i' files.txt

This passes the shell variable $i into awk, then evaluates an expression that tests whether the number of records processed is the same as that variable. If the expression evaluates true, awk prints the line. For better performance, try:

$ awk -v i="$i" 'NR==i{print;exit}' files.txt

Like the second sed script above, this will quit after printing the line, so as to avoid traversing the rest of the file.

Plenty of ways you could do this by loading the file into an array as well, but those ways would take more memory and perform less well. I'd use one-liners if you can. :)

To take any of these one-liners and put it into your script, you already have the notation:

if expr "$i" : '[0-9][0-9]*$' >/dev/null; then
    b=$(sed -ne "${i}{p;q;}" files.txt)
else
    echo "ERROR: invalid line number" >&2; exit 1
fi

Good grief. The entire script should just be (untested):

awk -v nr="$1" 'NR==nr{printf "\nmyFile = new TFile(\"/MYPATHNAME/%s\");\n\n",$0 > ("MyMacro_"nr".C")}' files.txt

You can throw in a ;exit before the } if performance is an issue but I doubt if it will be.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM