การขยายท่อการเลื่อนหรือการเพิ่มประสิทธิภาพมีประสิทธิภาพมากขึ้นหรือไม่?


26

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

list="1 ant bat 5 cat dingo 6 emu fish 9 gecko hare 15 i j"

ดังนั้นฉันต้องการที่จะสามารถวนซ้ำในรายการและเข้าถึง 1,5,6,9 และ 15 เท่านั้น

แก้ไข:ฉันควรทำให้ชัดเจนว่าค่าที่ฉันพยายามรับจากรายการไม่ต้องแตกต่างในรูปแบบจากส่วนที่เหลือของรายการ สิ่งที่ทำให้พวกเขาพิเศษเป็นเพียงตำแหน่งของพวกเขาในรายการ (ในกรณีนี้ตำแหน่ง 1,4,7 ... ) ดังนั้นรายการอาจเป็นได้1 2 3 5 9 8 6 90 84 9 3 2 15 75 55แต่ฉันยังต้องการหมายเลขเดิม และฉันต้องการที่จะทำมันโดยสมมติว่าฉันไม่รู้ความยาวของรายการ

วิธีการที่ฉันเคยคิดคือ:

วิธีที่ 1

set $list
found=false
find=9
count=1
while [ $count -lt $# ]; do
    if [ "${@:count:1}" -eq $find ]; then
    found=true
    break
    fi
    count=`expr $count + 3`
done

วิธีที่ 2

set list
found=false
find=9
while [ $# ne 0 ]; do
    if [ $1 -eq $find ]; then
    found=true
    break
    fi
    shift 3
done

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

found=false
find=9
count=1
num=`echo $list | cut -d ' ' -f$count`
while [ -n "$num" ]; do
    if [ $num -eq $find ]; then
    found=true
    break
    fi
    count=`expr $count + 3`
    num=`echo $list | cut -d ' ' -f$count`
done

ดังนั้นสิ่งที่จะมีประสิทธิภาพมากที่สุดหรือฉันขาดวิธีที่ง่ายกว่านี้?


10
ฉันจะไม่ใช้เชลล์สคริปต์ในตอนแรกถ้าประสิทธิภาพเป็นเรื่องสำคัญ รายการของคุณใหญ่แค่ไหนที่สร้างความแตกต่าง?
Barmar


2
หากไม่มีการทำสถิติเกี่ยวกับปัญหาจริงของคุณคุณจะไม่รู้อะไรเลย ซึ่งรวมถึงการเปรียบเทียบกับ "การเขียนโปรแกรมใน awk" เป็นต้นหากสถิติมีราคาแพงเกินไปการค้นหาประสิทธิภาพอาจไม่คุ้มค่า
David Tonhofer

2
เลวี, อะไรคือ "ความมีประสิทธิภาพ" ในนิยามของคุณ? คุณต้องการค้นหาวิธีการย้ำเร็วขึ้นหรือไม่
Sergiy Kolodyazhnyy

คำตอบ:


18

awkสวยเรียบง่ายด้วย นี่จะทำให้คุณได้รับคุณค่าของทุกฟิลด์ที่สี่สำหรับการป้อนข้อมูลของความยาวใด ๆ :

$ awk -F' ' '{for( i=1;i<=NF;i+=3) { printf( "%s%s", $i, OFS ) }; printf( "\n" ) }' <<< $list
1 5 6 9 15

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

หรือหากคุณต้องการให้ฟิลด์เหล่านั้นเป็นตัวอย่างตามที่ระบุในตัวอย่าง:

$ awk -F' ' '{ print $1, $4, $7, $10, $13 }' <<< $list
1 5 6 9 15

สำหรับคำถามเกี่ยวกับประสิทธิภาพเส้นทางที่ง่ายที่สุดคือการทดสอบวิธีการนี้หรือวิธีอื่น ๆ ของคุณและใช้timeเพื่อแสดงว่าใช้เวลานานแค่ไหน คุณสามารถใช้เครื่องมือต่าง ๆstraceเพื่อดูว่าระบบมีการเรียกใช้งานอย่างไร การใช้งานของtimeดูเหมือนว่า:

$ time ./script.sh

real    0m0.025s
user    0m0.004s
sys     0m0.008s

คุณสามารถเปรียบเทียบผลลัพธ์นั้นระหว่างวิธีการที่แตกต่างกันเพื่อดูว่าวิธีใดมีประสิทธิภาพมากที่สุดในแง่ของเวลา เครื่องมืออื่น ๆ สามารถใช้สำหรับการวัดประสิทธิภาพอื่น ๆ


1
จุดดี @MichaelHomer; ฉันได้เพิ่มการจัดการกับคำถามที่ว่า "ฉันจะทราบได้อย่างไรว่าวิธีใดมีประสิทธิภาพมากที่สุด"
DopeGhoti

2
@LeviUzodike เกี่ยวกับechovs <<<, "เหมือนกัน" นั้นแข็งแกร่งเกินคำ อาจกล่าวได้ว่าเกือบจะเหมือนกับstuff <<< "$list" printf "%s\n" "$list" | stuffเกี่ยวกับechovs printfฉันนำคุณไปสู่คำตอบนี้
JoL

5
@DopeGhoti จริง ๆ แล้วมันทำ <<<เพิ่มบรรทัดใหม่ในตอนท้าย สิ่งนี้คล้ายกับวิธีการ$()ลบ newline ออกจากปลาย นี่เป็นเพราะบรรทัดถูกยกเลิกโดยการขึ้นบรรทัดใหม่ <<<ฟีดนิพจน์เป็นบรรทัดดังนั้นจะต้องถูกยกเลิกโดยขึ้นบรรทัดใหม่ "$()"รับบรรทัดและจัดเตรียมเป็นอาร์กิวเมนต์ดังนั้นจึงเหมาะสมที่จะแปลงโดยการลบ newline ที่ยกเลิก
JoL

3
@LeviUzodike awk เป็นเครื่องมือที่ไม่ได้รับความนิยม มันจะทำให้ทุกปัญหาดูเหมือนซับซ้อนแก้ไขได้ง่าย โดยเฉพาะอย่างยิ่งเมื่อคุณพยายามเขียน regex ที่ซับซ้อนสำหรับบางสิ่งบางอย่างเช่น sed คุณมักจะประหยัดเวลาได้ด้วยการเขียนขั้นตอนเป็น awk แทน เรียนรู้ว่ามันจะจ่ายเงินปันผลมาก
Joe

1
@LeviUzodike: ใช่awkเป็นไบนารีแบบสแตนด์อโลนที่ต้องเริ่มต้น ซึ่งแตกต่างจากภาษา Perl หรือโดยเฉพาะอย่างยิ่ง Python ล่าม awk เริ่มต้นขึ้นอย่างรวดเร็ว (ยังคงทั้งหมด linker แบบไดนามิกค่าใช้จ่ายทั่วไปของการโทรระบบไม่กี่ แต่ awk เพียงใช้ libc / libm และ libdl เช่นใช้straceเพื่อตรวจสอบระบบโทรของการเริ่มต้น awk . เชลล์จำนวนมาก (เช่นทุบตี) ค่อนข้างช้าดังนั้นการเริ่มกระบวนการ awk หนึ่งกระบวนการอาจทำได้เร็วกว่าการวนซ้ำโทเค็นในรายการที่มีบิวด์อินเชลล์แม้สำหรับขนาดลิสต์ขนาดเล็ก และบางครั้งคุณสามารถเขียน#!/usr/bin/awkสคริปต์แทนของ#!/bin/shสคริปต์
Peter Cordes

35
  • กฎข้อแรกของการเพิ่มประสิทธิภาพของซอฟแวร์: Do not

    จนกว่าคุณจะรู้ว่าความเร็วของโปรแกรมเป็นปัญหาคุณไม่จำเป็นต้องคิดเกี่ยวกับความรวดเร็วของโปรแกรม หากรายการของคุณมีความยาวประมาณหรือประมาณ 100-1000 รายการคุณอาจไม่ได้สังเกตว่าใช้เวลานานเท่าใด มีโอกาสที่คุณจะใช้เวลาคิดเกี่ยวกับการเพิ่มประสิทธิภาพมากกว่าความแตกต่าง

  • กฎข้อที่สอง: การวัด

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

    ในโปรแกรมขนาดใหญ่การทำโปรไฟล์ก็มาที่นี่เช่นกัน ส่วนที่ช้าที่สุดอาจไม่ใช่ชิ้นที่คุณคิดว่าเป็น

  • ประการที่สามกฎข้อแรกของการเพิ่มประสิทธิภาพเชลล์สคริปต์: ไม่ได้ใช้เปลือก

    ใช่จริงๆ เชลล์จำนวนมากไม่ได้ทำเร็ว (ตั้งแต่เปิดตัวโปรแกรมภายนอกไม่จำเป็นต้อง) และพวกเขาอาจแยกวิเคราะห์บรรทัดของซอร์สโค้ดอีกครั้งในแต่ละครั้ง

    ใช้บางอย่างเช่น awk หรือ Perl แทน ในเกณฑ์มาตรฐานขนาดเล็กที่ฉันทำมันawkคือเร็วกว่าสิบเท่าของเชลล์ทั่วไปในการรันลูปแบบง่าย ๆ (โดยไม่มี I / O)

    อย่างไรก็ตามหากคุณใช้เชลล์ให้ใช้ฟังก์ชัน builtin ของเชลล์แทนคำสั่งภายนอก ที่นี่คุณกำลังใช้งานexprซึ่งไม่ได้สร้างขึ้นในเชลล์ใด ๆ ที่ฉันพบในระบบของฉัน แต่สามารถแทนที่ได้ด้วยการขยายเลขคณิตมาตรฐาน เช่นi=$((i+1))แทนการที่จะเพิ่มขึ้นi=$(expr $i + 1) iการใช้cutในตัวอย่างสุดท้ายของคุณอาจเปลี่ยนได้ด้วยการขยายพารามิเตอร์มาตรฐาน

    ดูเพิ่มเติม: เหตุใดการใช้เชลล์ลูปเพื่อประมวลผลข้อความจึงถือว่าไม่เหมาะสม

ขั้นตอนที่ # 1 และ # 2 ควรใช้กับคำถามของคุณ


12
# 0 อ้างถึงการขยายของคุณ :-)
Kusalananda

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

2
@DopeGhoti ดูเหมือนว่ากระสุนจะช้ากว่าปกติ ง่าย ๆ ในขณะที่ลูปดูเหมือนจะช้าdashกว่า> 25 เท่าgawkและdashเป็นกระสุนที่เร็วที่สุดที่ฉันทดสอบ ...
ilkkachu

1
@ โจมันคือ :) dashและbusyboxไม่สนับสนุน(( .. ))- ฉันคิดว่ามันเป็นส่วนขยายที่ไม่เป็นมาตรฐาน ++มีการกล่าวถึงอย่างชัดเจนว่าไม่จำเป็นเท่าที่ฉันจะสามารถบอกได้i=$((i+1))หรือ: $(( i += 1))เป็นสิ่งที่ปลอดภัย
ilkkachu

1
Re "คิดเวลามากขึ้น" : สิ่งนี้ละเลยปัจจัยสำคัญ มันทำงานบ่อยแค่ไหนและมีผู้ใช้กี่คน? หากโปรแกรมเสียเวลา 1 วินาทีซึ่งโปรแกรมสามารถแก้ไขได้โดยคิดเป็นเวลา 30 นาทีอาจเสียเวลาหากมีผู้ใช้เพียงรายเดียวเท่านั้นที่จะเรียกใช้ครั้งเดียว ในทางกลับกันหากมีผู้ใช้นับล้านคนนั่นคือหนึ่งล้านวินาทีหรือ 11 วันของเวลาผู้ใช้ หากรหัสสูญเสียผู้ใช้ไปหนึ่งล้านนาทีนั่นเป็นเวลาประมาณ2 ปีของผู้ใช้
agc

13

ฉันแค่จะให้คำแนะนำทั่วไปในคำตอบนี้ไม่ใช่มาตรฐาน การวัดประสิทธิภาพเป็นวิธีเดียวที่จะตอบคำถามเกี่ยวกับประสิทธิภาพได้อย่างน่าเชื่อถือ แต่เนื่องจากคุณไม่ได้บอกว่าคุณมีการจัดการข้อมูลมากน้อยเพียงใดและคุณใช้งานการดำเนินการนี้บ่อยแค่ไหนจึงไม่มีทางทำเกณฑ์มาตรฐานที่มีประโยชน์ได้ มีประสิทธิภาพมากขึ้นสำหรับ 10 รายการและอะไรที่มีประสิทธิภาพมากกว่าสำหรับ 1000000 รายการมักไม่เหมือนกัน

ตามกฎทั่วไปของหัวแม่มือการเรียกใช้คำสั่งภายนอกนั้นมีราคาแพงกว่าการทำอะไรบางอย่างกับการสร้างเชลล์บริสุทธิ์ตราบใดที่รหัสเชลล์บริสุทธิ์ไม่เกี่ยวข้องกับการวนซ้ำ ในทางกลับกัน shell loop ที่วนซ้ำสตริงขนาดใหญ่หรือสตริงจำนวนมากมีแนวโน้มที่จะช้ากว่าการเรียกใช้หนึ่งของเครื่องมือพิเศษ ตัวอย่างเช่นการวนลูปของคุณcutอาจสังเกตได้ช้าในทางปฏิบัติ แต่ถ้าคุณพบวิธีที่จะทำสิ่งทั้งหมดด้วยการcutเรียกใช้ครั้งเดียวที่น่าจะเร็วกว่าการทำสิ่งเดียวกันกับการจัดการสตริงในเชลล์

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

อย่าโทรexprไปหาเลขคณิตหากคุณกังวลเกี่ยวกับประสิทธิภาพ ที่จริงแล้วอย่าโทรexprไปทำการคำนวณทางคณิตศาสตร์เลย exprเปลือกหอยได้ในตัวในการคำนวณซึ่งเป็นที่ชัดเจนและเร็วกว่าการกล่าวอ้าง

คุณดูเหมือนจะใช้ bash เนื่องจากคุณใช้ bash constructs ที่ไม่มีอยู่ใน sh แล้วทำไมคุณไม่ใช้อาเรย์ล่ะ? อาเรย์เป็นวิธีแก้ปัญหาที่เป็นธรรมชาติที่สุดและมีแนวโน้มว่าจะเร็วที่สุด โปรดสังเกตว่าดัชนีอาร์เรย์เริ่มต้นที่ 0

list=(1 2 3 5 9 8 6 90 84 9 3 2 15 75 55)
for ((count = 0; count += 3; count < ${#list[@]})); do
  echo "${list[$count]}"
done

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

# List elements must not contain whitespace or ?*\[
list='1 2 3 5 9 8 6 90 84 9 3 2 15 75 55'
set $list
count=1
while [ $count -le $# ]; do
  eval "value=\${$count}"
  echo "$value"
  count=$((count+1))
done

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

# List elements must not contain whitespace or ?*\[
list='1 2 3 5 9 8 6 90 84 9 3 2 15 75 55'
set $list
while [ $# -ge 1 ]; do
  echo "$1"
  shift && shift && shift
done

วิธีการใดที่เร็วกว่านั้นขึ้นอยู่กับเชลล์และจำนวนองค์ประกอบ

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

# List elements must be separated by a single space (not arbitrary whitespace)
list='1 2 3 5 9 8 6 90 84 9 3 2 15 75 55'
while [ -n "$list" ]; do
  echo "${list% *}"
  case "$list" in *\ *\ *\ *) :;; *) break;; esac
  list="${list#* * * }"
done

" ในอีกทางหนึ่งเชลล์วนที่วนซ้ำสตริงใหญ่หรือสตริงจำนวนมากน่าจะช้ากว่าการเรียกใช้หนึ่งของเครื่องมือที่มีวัตถุประสงค์พิเศษ " แต่ถ้าเครื่องมือนั้นมีลูปเหมือน awk? @ikkachu กล่าวว่า awk loops นั้นเร็วกว่า แต่คุณจะบอกว่าถ้ามี <1,000 เขตข้อมูลที่จะวนซ้ำ, ประโยชน์ของการวนซ้ำที่เร็วขึ้นจะไม่เกินค่าใช้จ่ายในการโทร awk เนื่องจากเป็นคำสั่งภายนอก (สมมติว่าฉันสามารถทำงานแบบเดียวกัน ลูปกับการใช้คำสั่งในตัวเท่านั้น)?
Levi Uzodike

@LeviUzodike โปรดอ่านย่อหน้าแรกของคำตอบของฉัน
Gilles 'หยุดความชั่วร้าย' ใน

คุณสามารถแทนที่shift && shift && shiftด้วยshift 3ในตัวอย่างที่สามของคุณยกเว้นว่าเชลล์ที่คุณใช้ไม่รองรับ
Joe

2
@Joe ที่จริงแล้วไม่มี shift 3จะล้มเหลวหากมีข้อโต้แย้งเหลืออยู่น้อยเกินไป คุณต้องการบางสิ่งเช่นif [ $# -gt 3 ]; then shift 3; else set --; fi
Gilles 'SO- หยุดความชั่วร้าย'

3

awkเป็นตัวเลือกที่ดีถ้าคุณสามารถประมวลผลทั้งหมดภายในสคริปต์ Awk มิฉะนั้นคุณเพียงวางท่อ Awk output ไปยังยูทิลิตี้อื่น ๆ เพื่อทำลายประสิทธิภาพที่เพิ่มawkขึ้น

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

อย่างไรก็ตามวิธีการไปป์ไลน์:

xargs -n3 <<< "$list" | while read -ra a; do echo $a; done | grep 9

ที่ไหน:

  • xargs จัดกลุ่มรายการที่คั่นด้วยช่องว่างออกเป็นสามชุดแต่ละรายการขึ้นบรรทัดใหม่
  • while read กินรายการนั้นและส่งออกคอลัมน์แรกของแต่ละกลุ่ม
  • grep กรองคอลัมน์แรก (สอดคล้องกับทุกตำแหน่งที่สามในรายการต้นฉบับ)

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

count=3
find=9
xargs -n "$count" <<< "$list" | while read -ra a; do echo $a; done | grep "$find"

เมื่อเราถามคำถามเกี่ยวกับ "ประสิทธิภาพ" อย่าลืมนึกถึง "ประสิทธิภาพตลอดชีวิตโดยรวม" การคำนวณนั้นรวมถึงความพยายามของผู้ดูแลในการรักษารหัสให้ทำงานและเราถุงเนื้อเป็นเครื่องจักรที่มีประสิทธิภาพน้อยที่สุดในการทำงานทั้งหมด


2

บางทีนี่อาจ?

cut -d' ' -f1,4,7,10,13 <<<$list
1 5 6 9 15

ขออภัยฉันไม่ชัดเจนก่อน แต่ฉันต้องการที่จะได้รับตัวเลขที่ตำแหน่งเหล่านั้นโดยไม่ทราบความยาวของรายการ แต่ขอบคุณฉันลืมตัดสามารถทำเช่นนั้น
Levi Uzodike

1

อย่าใช้คำสั่งเชลล์หากคุณต้องการให้มีประสิทธิภาพ จำกัด ตัวคุณเองที่ท่อการเปลี่ยนเส้นทางการทดแทน ฯลฯ และโปรแกรม นั่นเป็นสาเหตุxargsและparallelสาธารณูปโภคมีอยู่ - เพราะทุบตีในขณะที่ลูปไม่มีประสิทธิภาพและช้ามาก ใช้ลูป bash เป็นวิธีแก้ไขครั้งสุดท้ายเท่านั้น

list="1 ant bat 5 cat dingo 6 emu fish 9 gecko hare 15 i j"
if 
    <<<"$list" tr -d -s '[0-9 ]' | 
    tr -s ' ' | tr ' ' '\n' | 
    grep -q -x '9'
then
    found=true
else 
    found=false
fi
echo ${found} 

awkแต่คุณควรจะได้รับอาจจะค่อนข้างเร็วด้วยความดี


ขออภัยฉันไม่ชัดเจนก่อนหน้านี้ แต่ฉันกำลังมองหาโซลูชันที่สามารถแยกค่าตามตำแหน่งในรายการเท่านั้น ฉันเพิ่งสร้างรายการดั้งเดิมเช่นนั้นเพราะฉันต้องการให้ชัดเจนค่าที่ฉันต้องการ
Levi Uzodike

1

ในความคิดของฉันทางออกที่ชัดเจน (และอาจเป็นสิ่งที่มีประสิทธิภาพมากที่สุด) คือการใช้ตัวแปร RS และ ORS awk:

awk -v RS=' ' -v ORS=' ' 'NR % 3 == 1' <<< "$list"

1
  1. ใช้GNU sedและPOSIXเชลล์สคริปต์:

    echo $(printf '%s\n' $list | sed -n '1~3p')
  2. หรือbash's เปลี่ยนตัวพารามิเตอร์ :

    echo $(sed -n '1~3p' <<< ${list// /$'\n'})
  3. ไม่ใช่GNU ( เช่น POSIX ) sedและbash:

    sed 's/\([^ ]* \)[^ ]* *[^ ]* */\1/g' <<< "$list"

    หรือมากกว่าพกพาโดยใช้ทั้งPOSIX sedและเชลล์สคริปต์:

    echo "$list" | sed 's/\([^ ]* \)[^ ]* *[^ ]* */\1/g'

ผลลัพธ์ของสิ่งเหล่านี้:

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