ใช้ sed กับตัวแปรสตริงมากกว่าไฟล์


30

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

พิจารณาสิ่งต่อไปนี้:

~$x=$PATH
~$sed -i 's/:/ /g' $x

สิ่งนี้ล้มเหลวด้วย: ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว

นี่คือบางส่วนที่ฉันลอง:

~$ sed -i 's/:/ /g' | (read x) 
sed: no input files
~$ sed -i 's/:/ /g' | (read $x) 
bash: read: `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games': not a valid identifier
sed: no input files
~$ sed -i 's/:/ /g' | $(read x) 
sed: no input files
~$ sed -i 's/:/ /g' | $(read $x) 
bash: read: `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games': not a valid identifier
sed: no input files
~$ sed -i 's/:/ /g' < $(read $x) 
bash: read: `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games': not a valid identifier
bash: $(read $x): ambiguous redirect
~$ sed -i 's/:/ /g' < read $x 
bash: read: No such file or directory
~$ sed -i 's/:/ /g' < (read x) 
bash: syntax error near unexpected token `('
~$ sed -i 's/:/ /g' < $((read x)) 
bash: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games: syntax error: operand expected (error token is "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games")
~$ sed -i 's/:/ /g' < $((read $x)) 
bash: read /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games: division by 0 (error token is "usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games")
~$ sed -i 's/:/ /g' << $((read $x)) 
> ;^C
~$ sed -i 's/:/ /g' << $(read $x)
> ;^C
~$ sed -i 's/:/ /g' $x
sed: can't read /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games: No such file or directory
~$ sed -i 's/:/ /g' < $x
bash: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games: No such file or directory
~$ sed -i 's/:/ /g' < echo $x
bash: echo: No such file or directory
~$ sed -i 's/:/ /g' |  echo $x
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
sed: no input files

สามารถใช้งานได้หรือไม่ ฉันไม่ต้องการเขียนไฟล์ฉันไม่ต้องการเพียงแค่ฉันสามารถใช้ sed สำหรับตัวอย่างนี้หาก~$x=$PATH ~$sed -i 's/:/ /g' $xทำตามที่ฉันคาดหวังจริง ๆ แล้วฉันจะได้รับ:

/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /usr/games /usr/local/games

ซึ่งฉันสามารถกำหนดให้กับตัวแปรและใช้ในคำสั่งในอนาคตเช่น ls $x


1
x=$(echo "$x" | sed 's/:/ /g')?
heemayl

คำตอบ:


16

อาจจะ:

~$ x="$PATH"
~$ x="$(echo $x | sed 's/:/ /g')"
~$ echo "$x"
/usr/local/bin /usr/bin /bin /usr/local/games /usr/games

@ jOh --- สังเกตว่าที่sedนี่ไม่ทำงานกับ "ตัวแปรสตริง" (?) แต่ในอินพุตมาตรฐาน --- ซึ่งเป็นวิธีที่ควรจะเป็น
Rmano

ฉันคิดว่าป่วยทำคำขอคุณสมบัติเพื่อ sed devs
j0h

4
@ j0h สิ่งนี้ไม่เกี่ยวข้องกับsedมันเป็นคำถามว่าเชลล์เปลี่ยนทิศทางอินพุตอย่างไร sedจัดการกับอินพุตสตรีมและอ่านผ่านอินพุตมาตรฐาน ไม่ว่าจะเป็นไฟล์หรือไม่เกี่ยวข้อง มันสามารถรับอะไรก็ได้ตราบเท่าที่มันผ่านเข้ามาตรฐาน
terdon

38

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

sed 's/:/ /g' <<<"$PATH"

ไม่มีเหตุผลที่จะบันทึกในตัวแปรอื่นไม่มีอะไรที่คุณทำเช่นนี้จะส่งผลกระทบต่อค่าที่เก็บไว้ในตัวแปร คุณต้องมีผู้ดำเนินการที่ได้รับมอบหมาย ( =) สำหรับสิ่งนั้น ไวยากรณ์ที่ใช้ด้านบนเรียกว่า"here string"และใช้เฉพาะกับ bash, ksh และ zsh มันทำหน้าที่ส่งค่าของตัวแปรเป็นอินพุตไปยังโปรแกรมที่อ่านจากอินพุตมาตรฐาน

ฉันเขียนคำตอบเกี่ยวกับ U&Lที่แสดงตัวดำเนินการเชลล์ต่าง ๆ ทั้งหมดเช่นนี้ คุณอาจต้องการดู

โปรดทราบว่าคุณสามารถทำได้

echo "$PATH" | sed 's/:/ /g' 

ในที่สุดคุณไม่จำเป็นต้องทำsedสิ่งนี้จริงๆ คุณสามารถทำสิ่งทั้งหมดในทุบตีโดยตรง:

echo "${PATH//:/ }"

ด้านบนเป็นโครงสร้างการเปลี่ยนทุบตี รับตัวแปรรูป$varแบบpatและการแทนที่ ( rep) เพื่อแทนที่การเกิดขึ้นทั้งหมดpatด้วยrepคุณจะทำ

echo "${var//pat/rep}"

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

echo "${var/pat/rep}"

2
ขอบคุณสำหรับ 'การสร้างการเปลี่ยนทุบตี' ฉันสามารถใช้: "$ {1 / from / to}" ในฟังก์ชัน Bash เพื่อเปลี่ยนอาร์กิวเมนต์แรกเป็นพารามิเตอร์ที่ตามมา
AAAfarmclub
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.