มีทุบตีเทียบเท่ากับวัตถุท่อ PowerShell?


0

ใน PowerShell ฉันสามารถเรียกใช้สิ่งนี้ในหนึ่งซับ

Get-ChildItem | foreach {
  if ($_ -match '.+?\.py$' -eq $true) {
    $_ | Do-Thing -WithFile
  }
  if ($_ -match '.+?\.pdf$' -eq $true) {
    $_ | Do-Thing -WithOtherFile
  }
}

ชอบมาก

Get-ChildItem | foreach { if ($_ -match '.+?\.py$' -eq $true) { $_ | Do-Thing -WithFile } if ($_ -match '.+?\.pdf$' -eq $true) { $_ | Do-Thing -WithOtherFile } }

การทำงานเฉพาะของสิ่งนี้ที่ฉันชื่นชมคือการสามารถอ้างอิงวัตถุไปป์ไลน์ผ่าน $_ ที่จะใช้ในคำสั่งถัดไปและความสามารถในการดำเนินการตามเงื่อนไขขึ้นอยู่กับชิ้นส่วนแยกของเอาต์พุต | foreach {}.

ฉันรู้ว่าในทุบตีมันจะง่ายต่อการ grep หลายรูปแบบในครั้งเดียวผ่าน

> ls | egrep '\.py$|\.pdf$'

some_foo.py
some_bar.py
foo.pdf
bar.pdf

เป็นไปได้หรือไม่ที่จะขยายสิ่งนี้ในหนึ่งซับด้วยสิ่งที่มีอยู่ตามค่าเริ่มต้นที่ฉันสามารถทำเทียบเท่าได้

| foreach { if ($_ -match '.+?\.py$') {Do-Thing -With $_ } if (...) { Do-Thing -WithOther $_ } }

หรือ Bash เพียงเปลี่ยนเส้นทาง stdout ของคำสั่งหนึ่งไปยัง stdin ของอีกคำสั่งหนึ่ง ฉันพบว่ามีหลายอย่างที่ใช้กับไดนามิกนี้ใน PowerShell แต่ไม่เคยได้ยินเรื่องของ Bash

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

กำลังมองหา: $_ , | foreach {} เทียบเท่าที่ฉันสามารถแยกเอาต์พุตตรวจสอบเงื่อนไขบนมันจากนั้นสามารถอ้างอิงส่วนแยกของเอาต์พุตผ่านชื่อบางชื่อ ในกรณีของ PS $ _

ฉันรู้ว่ามีหลายวิธีที่ PS แตกต่างจาก Bash อย่างมากดังนั้นฉันจะไม่แปลกใจหากนี่เป็น PS เฉพาะ

เพื่อบริบทที่ดีกว่านี่คือตัวอย่างใน PS ที่คุณจะค้นหาไฟล์ซ้ำด้วย python และส่วนขยาย pdf และสร้างบันทึกของไฟล์เหล่านั้นในไฟล์ข้อความที่เกี่ยวข้อง

Get-ChildItem -Recurse | foreach {
  if ($_ -match '.+?\.py$' -eq $true) {
    $_ | Out-File -encoding utf8 -Append py_list.txt
  }
  if ($_ -match '.+?\.pdf$' -eq $true) {
    $_ | Out-File -encoding utf8 -Append pdf_list.txt
  }
}

คำตอบ:


1

ใช่ (เกือบ) และไม่ Bash ไม่รองรับ pipelining 'object' ในตอนแรก - pipelines ของมันแม้จะอยู่ภายในก็ยังคงถูกสร้างขึ้นจาก subprocesses และ stdio สามัญ (ซึ่งเป็น bytestream) และดังนั้นคุณสามารถโต้ตอบกับบรรทัดธรรมดาของ ข้อความ (เช่นรายการเส้นทางไฟล์แบบบรรทัดต่อบรรทัด) ไม่ใช่วัตถุที่ซับซ้อน

ดังนั้นค่าที่ใกล้เคียงที่สุดจะเท่ากับ while read -r <var>; do ...; done. เพิ่มเติมในภายหลัง


ของคุณ โดยเฉพาะ งานสามารถ ดีที่สุด จัดการโดยใช้วิธีง่ายๆ for <var> in <words> วนรอบด้วย สัญลักษณ์ :

for file in *; do
    if [[ $file == *.py ]]; then
        do_something_with "$file"
    elif [[ $file == *.pdf ]]; then
        do_something_else --with "$file"
    fi
done

คุณไม่จำเป็นต้องทำซ้ำการตรวจสอบอย่างชัดเจน - คุณสามารถมีสองลูปแทน:

for file in *.py; do
    do_something_with "$file"
done

for file in *.pdf; do
    do_something_else --with "$file"
done

ให้ทำเช่นเดียวกัน ซ้ำ คุณสามารถ a) ใช้สัญลักษณ์แทนซ้ำของ Bash:

shopt -s globstar

for file in **/*; do
    if ...; then ...; fi
done

หรือ b) ใช้ find และวนรอบ แต่ละบรรทัดใน stdin :

find . -type f | while read -r file; do
    if [[ $file == *.py ]]; then
        ...
    fi
done

(ใช่ฉันควรจะใช้ IFS="" read -r <var> เพื่อจัดการกับชื่อไฟล์ที่เกิดขึ้นด้วยการเว้นวรรค - แต่โชคดีที่ฉันไม่มีชื่อใด ๆ ในระบบของฉันดังนั้นฉันจะไม่รำคาญ

อีกครั้งคุณสามารถข้ามการตรวจสอบชื่อไฟล์ด้วยตนเองและขอสิ่งที่คุณต้องการล่วงหน้า

shopt -s globstar

for file in **/*.pdf; do
    do_something_with "$file"
done

ตัวแปร b:

find . -type f -name "*.pdf" | while read -r file; do
    do_something_with "$file"
done

เหมือนกัน แต่ใช้ประโยชน์จาก หา ตัวเลือก -exec:

find . -type f -name "*.pdf" -exec do_something_with {} \;

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