การสร้างสคริปต์พร้อมตัวเลือกเพื่อเข้าถึงไดเรกทอรีและไฟล์ต่างๆ


12

ฉันดิ้นรนเป็นเวลานานในการเขียนสคริปต์ซึ่งจะมี 2 ข้อโต้แย้ง 1 ขอให้เลือกหนึ่งปีและ 2 ขอให้เลือกว่าฉันต้องการแสดงขั้นต่ำสูงสุดสูงสุดเฉลี่ยหรือทั้งหมดเป็นบรรทัดสุดท้ายจากไฟล์ที่เกี่ยวข้อง ถึงปีที่เลือก

โดยทั่วไปฉันมีไดเรกทอรีที่มีไดเรกทอรีย่อยของปีต่างๆ (2000, 2001, 2002 ฯลฯ ) ในไดเรกทอรีเหล่านั้นเป็นไดเรกทอรีย่อยสำหรับเดือนและวันที่มี (a) ไฟล์ (s) แจ้งเกี่ยวกับประชากร (ไม่ใช่ข้อมูลจริง) ที่แตกต่างกัน เมืองเป็นบรรทัดสุดท้าย นั่นเป็นส่วนหนึ่งของแผนผังไดเรกทอรี:

.
|-- 2000
|   |-- 01
|   |   `-- 18
|   |       `-- ff_1177818640
|   |-- 02
|   |   |-- 02
|   |   |   `-- ff_1669027271
|   |   |-- 03
|   |   |   `-- ff_234075290
|   |   |-- 10
|   |   |   `-- ff_1584524530
|   |   |-- 14
|   |   |   `-- ff_113807345
|   |   `-- 17
|   |       `-- ff_1452228827
|   |-- 03
|   |   |-- 06
|   |   |   `-- ff_58914249
|   |   `-- 11
|   |       `-- ff_2828212321
|   |-- 04
|   |   `-- 17
|   |       `-- ff_302131884
|   |-- 06
|   |   `-- 13
|   |       `-- ff_2175615745
|   |-- 07
|   |   |-- 07
|   |   |   `-- ff_918426998
|   |   `-- 24
|   |       `-- ff_2808316425
|   |-- 08
|   |   `-- 27
|   |       `-- ff_1449825497
|   |-- 09
|   |   `-- 19
|   |       `-- ff_110255856
|   `-- 12
|       `-- 08
|           `-- ff_1621190
|-- 2001
|   |-- 03
|   |   `-- 21
|   |       `-- ff_517010375
|   |-- 05
|   |   `-- 27
|   |       `-- ff_1458621098
|   |-- 06
|   |   |-- 07
|   |   |   `-- ff_155853916
|   |   |-- 25
|   |   |   |-- ff_2382312387
|   |   |   `-- ff_270731174
|   |   `-- 29
|   |       `-- ff_3228522859
|   |-- 07
|   |   `-- 28
|   |       `-- ff_3215021752
|   |-- 09
|   |   `-- 24
|   |       `-- ff_1080314364
|   `-- 11
|       `-- 24
|           `-- ff_2313722442

ไฟล์ทั้งหมดถูกฟอร์แมทด้วยวิธีเดียวกัน:

2019-04-03
Wednesday
Newcastle-upon-Tyne
255362

ฉันต้องเขียนสคริปต์เพื่อขอให้ปีที่ฉันต้องการ (เลือกไดเรกทอรีนั้น) แล้วถามว่าฉันต้องการเฉลี่ยต่ำสุดสูงสุดหรือทั้งหมดข้างต้นจะแสดงสำหรับประชากร (ซึ่งเป็นบรรทัดสุดท้ายของไฟล์)

นี่คือสิ่งที่ฉันมี:

#!/bin/bash

function min () {
    echo $(sort -n populations | head -1)
}

function max () {
    echo $(sort -n populations | tail -1)
}

function avg () {
    count=0
    sum=0
    while read line ; do
        num='echo ${line#* }'
        sum='expr $sum + $num'
        count='expr $count + 1'
    done < populations
    avg='expr $sum / $count'
    echo $avg
}

echo "Please enter the year: "
read s1
echo "
        Enter an option:
        1. Minimum
        2. Maximum
        3. Average
        4. All"
read s2
#echo $s2
for file in $(find ~/filesToSort/$s1 -type f) ; do
    tail -1 $file >> populations
done
echo $(cat populations)
#min
#max
#avg
rm populations

สิ่งนี้ช่วยให้ฉันเลือกไดเรกทอรี แต่ไม่ได้ให้คำตอบที่ฉันต้องการเพียงคายบรรทัดสุดท้ายของไฟล์


ดังนั้นคุณต้องการที่จะทำคณิตศาสตร์จากตัวเลขที่เก็บไว้ในไฟล์ 'ประชากร'?
cmak.fr

คำตอบ:


7

หากฉันใช้สิ่งนี้ในการทุบตีฉันจะทำสิ่งต่อไปนี้ ฉันจะไม่แสดงความคิดเห็นกับมันมาก: อย่าลังเลที่จะถามคำถามเฉพาะเจาะจง - ตรวจสอบหน้า bash man ก่อนถ้าคุณไม่ทราบว่าคำสั่งเฉพาะทำงานอย่างไร

#!/bin/bash

# read the population from all the files
# map the filename to it's population figure
declare -A population
while IFS= read -d '' -r filename; do
    population["$filename"]=$(tail -1 "$filename")
done < <(find . -type f -print0)

# prompt the user for the year
read -rp "What year? " year

# find the relevant files for that year
year_files=()
for filename in "${!population[@]}"; do
    [[ $filename == ./"$year"/* ]] && year_files+=("$filename")
done
if [[ "${#year_files[@]}" -eq 0 ]]; then
    echo "No files for year '$year'"
    exit 1
fi

PS3="Select a function to calculate: "
select func in minimum maximum average quit; do
    case $func in
        minimum)
            min=${population[${year_files[0]}]}
            for file in "${year_files[@]}"; do
                if (( min > ${population[$file]} )); then
                    min=${population[$file]}
                fi
            done
            echo "Minimum for $year is $min"
            ;;
        maximum)
            max=${population[${year_files[0]}]}
            for file in "${year_files[@]}"; do
                if (( max < ${population[$file]} )); then
                    max=${population[$file]}
                fi
            done
            echo "Maximum for $year is $max"
            ;;
        average)
            count=0 sum=0
            for file in "${year_files[@]}"; do
                (( sum += ${population[$file]} ))
                (( count++ ))
            done
            echo "Average for $year is $(( sum / count ))"
            ;;
        quit) exit ;;
    esac
done

ควรมีตัวเลือกอื่นที่เลือกเป็น "ทั้งหมด"
αғsнιη

5

ฉันเขียนawkสคริปต์ง่าย ๆซึ่งเหมือนกับสิ่งที่คุณทำ:

# read 'year' & 'option' from user
# or you can pass as argument to the command $1<-->$year & $2<-->$option

find /path/to/$year -type f -exec \
    awk -v select=$option '
        FNR==4 { sum+=$0; avg=sum/++count; 
                 max=(max>=$0?max:$0);
                 if (count==1) min=$0;
        }
        count>1 { min=(min<=$0?min:$0);
        }
    END{ stats=min","max","avg","min"\n"max"\n"avg;
         split(stats, to_print,",");
         print to_print[select];
    }' {} +

คำอธิบายแบบอินไลน์:

# read 'year' & 'option' from user
# or you can pass as argument to the command $1<-->$year & $2<-->$option

find /path/to/$year -type f -exec \
# find all files under "/path/to/$year". $year will be substitute with the value 
# of 'year' variable read from user-input or replace it with '$1' as first argument to the command

    awk -v select=$option '
    # read the value of shell 'option' variable into an awk 'select' variable 
    # replace with '$2' as argument to the command

        FNR==4 { sum+=$0; avg=sum/++count;
        # if it's 4th line of each input file, sum-up the value into 'sum' variable
        # and calculate the 'avg' too when 'count' will increment once each 4th record in a file is read

                 max=(max>=$0?max:$0);
                 # its a Ternary operator (condition?if-true:if-false) and finding maximum value

                 if (count==1) min=$0;
                 # keep the first file's 4th line's value as minimum. you could use `NR==4` instead
        }
        count>1 { min=(min<=$0?min:$0);
        # same as max, update the 'min' if value in current file is smaller than 'min' in previous file
        }
    END{ stats=min","max","avg","min"\n"max"\n"avg;
    # saving all variables' value into single variable with comma separated. I used <min"\n"max"\n"avg> as 
    # fourth element which we will use it as "All" option that each separated with newlines.

         split(stats, to_print, ",");
         # building an array called 'to_print' from 'stats' variable above with comma separator to distinguish 
         # the elements from each other.

         print to_print[select];
         # this will print the element which user-input as an option.
         # if input 1: will print 'min'
         # if input 2: will print 'max'
         # if input 3: will print 'avg'
         # if input 4: will print 'min' \n 'max' '\n' avg
    }' {} +

0

ตามที่เขียนไว้สคริปต์จะไม่ทำอะไรเลยนอกจากพิมพ์ประชากรเพราะ avg ฯลฯ ถูกใส่ความคิดเห็นไว้

ในการคำนวณ avg ประชากรเหล่านั้นจะต้องถูกส่งไปยังฟังก์ชัน avg () พร้อมกับบางสิ่งบางอย่างเช่น ...

echo "$(cat populations | avg)"

จะมีการเพิ่มบรรทัดที่คล้ายกันสำหรับ min () และ max ()

คุณสามารถใช้caseคำสั่งเพื่อเรียกใช้ฟังก์ชันที่เหมาะสม ...

  :
done
#
case s2
  1|4) echo "$(cat populations | min)" ;;&
  2|4) echo "$(cat populations | max)" ;;&
  3|4) echo "$(cat populations | avg)";;
esac
#
rm populations

1|4) echo ...ทำให้เกิดการสะท้อนให้ทำงานถ้า 1 หรือ 4 จะป้อน ดังนั้นทั้ง 3 จะดำเนินการถ้า 4 ถูกป้อน


1
PerlDuck - คุณถูกต้อง (แต่เป็น ';; &') การแก้ไข ขอบคุณ
DocSalvager

0

ขอบคุณสำหรับคำตอบทั้งหมดนี่คือสิ่งที่ฉันได้รับ:

#!/bin/bash
### Returns the minimum value by sorting the population file's data and displaying the top line.
 function min () {
         echo "Minimum Population: "$(sort -n populations | head -1)
 }
  ### Returns the maximum value by sorting the population file's data and displaying the bottom line.
 function max () {
         echo "Maximum Population: "$(sort -n populations | tail -1)
 }
  ### A function to return the average number of population.
 function avg () {
         count=0
         sum=0
         while read line ; do
                 num=`echo ${line#* }`
                 sum=`expr $sum + $num`
                 count=`expr $count + 1`
         done < populations
         avg=`expr $sum / $count`
         echo "Average Population: "$avg
 }
  ### Advises what the script does and asks for an imput of a year.
 echo "
         ######################
         # Population adviser #
         ######################
          Please enter the year: "
 read s1
  ### If statement checking the year entered is available, if not then the user is informed of invalid selection and program terminates.
 if [[ $s1 -ge 2000 && $s1 -le 2019 && $s1 -ne 2009 ]] ; then
         continue 2>/dev/null
 else
         echo "The year you entered is not valid, program terminating"
         exit
 fi
  ### Prompts user for input
 echo "
         Enter an option:
         1. Minimum
         2. Maximum
         3. Average
         4. All
  -----(minimum) (maximum) (average) (all)-----
 "
 read s2
  ### Loops through all files within the given directory path and appends the population of each file to the population list
 for file in $(find ~/filesToSort/$s1 -type f) ; do
         tail -1 $file >> populations
 done
  ### If statement to validate user input and then use the function(s) required
 if [ "$s2" == "minimum" ] ; then
         min
 elif [ "$s2" == "maximum" ] ; then
         max
 elif [ "$s2" == "average" ] ; then
         avg
 elif [ "$s2" == "all" ] ; then
         min
         max
         avg
 else
         echo "The option you chose is invalid, program terminating"
         rm populations
         exit
 fi
  ### Removes "populations" file upon completion
 rm populations

เมื่อเลือกตัวเลือก (1-4) แทนที่จะใส่ตัวเลขต้องใส่คำแทนซึ่งฉันเกลียด แต่ถูกขอให้ทำแบบนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.