bash - แทนที่ช่องว่างด้วยบรรทัดใหม่


70

ฉันจะแทนที่ช่องว่างด้วยบรรทัดใหม่ในอินพุตเช่น:

/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5 ฯลฯ ...

เพื่อรับสิ่งต่อไปนี้:

/path/to/file
/path/to/file2
/path/to/file3
/path/to/file4
/path/to/file5

บันทึก

ฉันโพสต์คำถามนี้เพื่อช่วยผู้ใช้รายอื่นมันไม่ง่ายเลยที่จะหาคำตอบที่มีประโยชน์ใน UNIX SE จนกว่าฉันจะเริ่มพิมพ์คำถามนี้ หลังจากนั้นฉันพบสิ่งต่อไปนี้:

คำถามที่เกี่ยวข้อง

ฉันจะค้นหาและแทนที่ด้วยบรรทัดใหม่ได้อย่างไร



ls / path / to / | xargs echo | sed 's / \ s \ + / \ n / g'
SD

คำตอบ:


125

ใช้trคำสั่ง

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5"\
| tr " " "\n"

พบได้ที่http://www.unix.com/shell-programming-scripting/67831-replace-space-new-line.html


1
tr เป็นความคิดแรกของฉันเช่นกันแม้ว่าจะมีหลายวิธีที่จะทำ! นี่เป็นสิ่งที่trค่อนข้างแน่นอนสำหรับ!
Rob

5
+1 แต่เป็นความคิดเห็น: นั่นไม่ได้ผลหากชื่อไฟล์มีช่องว่าง
Bonsi Scott

20

ในกรณีนี้ฉันจะใช้ printf:

printf '%s\n' /path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5

หากมีช่องว่างภายในหนึ่งในพา ธ คุณสามารถอ้างอิง filepath นั้นเพื่อป้องกันไม่ให้ถูกแบ่งบนช่องว่าง:

printf '%s\n' /path/to/file '/path/to/file with spaces' /path/to/another/file

ในการแปลงข้อความโดยทั่วไปtrเป็นทางออกที่ดีที่สุดของคุณตามที่อธิบายไว้ในคำตอบที่มีอยู่


1
บันทึกย่อจากอนาคต: ขอบคุณสำหรับการโพสต์โซลูชันนี้มันน่าเชื่อถือมากสำหรับฉันเปรียบเทียบกับการใช้ "echo"
Liesmith

5

สมมติว่าคุณมีสตริงที่มีช่องว่างเป็นตัวคั่น:

newline_separated=${space_separated// /$'\n'}

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

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

printf '%s\n' "$@"

หากคุณมีชื่อไฟล์พื้นที่แยกออกจากกันและคุณต้องการที่จะนำพวกเขาในอาร์เรย์ที่จะทำงานกับพวกเขาคุณสามารถใช้การขยายตัวของตัวแปร unquoted จะแยกค่าที่ตัวอักษรบนIFS(คุณจะต้องปิดการขยายตัวสัญลักษณ์แทนด้วยset -fมิฉะนั้น glob รูปแบบจะถูกขยายในค่า):

space_separated_list='/path/to/file1 /path/to/file2 /path/to/file3'
IFS=' '; set -f
eval "array=(\$space_separated_list)"
for x in "${array[@]}"; do 

คุณสามารถแค็ปซูลในฟังก์ชันที่เรียกคืนการ-fตั้งค่าและมูลค่าIFSเมื่อเสร็จสิ้น:

split_list () {
  local IFS=' ' flags='+f'
  if [[ $- = *f* ]]; then flags=; fi
  set -f
  eval "$1=($2)"
  set $flags
}
split_list array '/path/to/file1 /path/to/file2 /path/to/file3'
for x in "${array[@]}"; do 

เปลี่ยนคำตอบที่ถูกต้องเป็นคำตอบนี้ ฉันคิดว่ามันถูกต้องมากขึ้นในการค้นคว้าวิธีที่ฉันไปยังรายการที่คั่นด้วยช่องว่างและดึงข้อมูลนั้นในอีกทางหนึ่ง มันจะเจ๋งสำหรับผู้เรียนอย่างฉันถ้าคุณแสดงความคิดเห็นเล็กน้อยกับ snipnet ของคุณบอกเราว่าสิ่งต่าง ๆ เช่น local var IFS หรือเงื่อนไข $ - = fทำอย่างไร สิ่งที่คนแบบนั้นใช้ทุบตีไม่กี่ครั้งก็ไม่รู้
laconbass

@laconbass ฉันได้เพิ่มคำอธิบายสั้น ๆ ค้นหาset -fและIFSในคู่มือทุบตีหากคุณต้องการรายละเอียดทั้งหมด ดูเพิ่มเติมที่unix.stackexchange.com/questions/16192/…
Gilles

@ Guilles คำอธิบายสั้น ๆ นั้นเพียงพอสำหรับฉันและฉันคิดว่ามันจะเป็นของคนอื่น ๆ อีกมากมาย Ty สำหรับเวลาของคุณ
laconbass

การตั้งค่าIFSในเครื่องไม่มีผล
Eliran Malka

@EliranMalka ฉันไม่ทราบว่าคุณหมายถึงอะไร หากสคริปต์ไม่ทำงานอย่างที่คุณคิดคุณควรถามคำถามที่นี่
Gilles

4

ใช้การได้อย่างเต็มที่ !!

sed 's/\s\+/\n/g' file

ข้างต้นบอกว่าจะแทนที่หนึ่งตัวหรือมากกว่าช่องว่างอักขระ (\ s +) ด้วย newline (\ n)

นี่คือมากหรือน้อย:

'substitute /one space or more/ for /newline/ globally'

1
แทนที่การเปลี่ยนแปลงด้วยการแทนที่นั่นคือสิ่งที่แท้จริงหมายถึง!
Rob

@ Rob ขอบคุณจำไว้ว่าคุณสามารถแก้ไขคำตอบของผู้อื่นได้
MGP

1
หากคุณมีช่องว่างหลายช่องระหว่างข้อความคุณจะได้รับบรรทัดว่าง คุณต้องเพิ่ม '+' หลัง \ s เพื่อระบุว่าคุณต้องการจับคู่อย่างน้อยหนึ่งช่องว่างตามที่ระบุไว้ในที่เดียว กล่าวคือ sed 's / \ s + / \ n / g'
DarkHeart

4

เป็นทางเลือกแทนtrจาก @laconbass คุณสามารถใช้xargsในกรณีนี้:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4  /path/to/file5"\
| xargs -n1

ข้อดีก็คือการทำงานแม้จะมีช่องว่างหลายที่trไม่ได้


0

นี่คือวิธีที่ฉันทำ:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5" | sed 's/ /\
'/g

สังเกตการใช้ปุ่ม Enter หลังจากแบ็กสแลชในsedคำสั่ง


สิ่งที่ prons และ cons มีsedมากกว่าtr?
laconbass

ระดับความสะดวกสบายของคุณ :-) ฉันคิดว่าคุณสามารถทำอะไรได้มากกว่าsedเพราะเป็นบรรณาธิการมากกว่าแค่แปลตัวละคร
unxnut

4
sedสามารถทำอะไรได้มากกว่านี้ แต่มันเกินความจริงสำหรับสิ่งนี้ trเป็นเครื่องมือที่เหมาะสมสำหรับงานนี้ แต่ความรู้sedและ regexes จะมีประโยชน์ในภายหลังอย่างแน่นอน!
Rob

0

อีกวิธีหนึ่งโดยสมมติว่าบรรทัดอยู่ในตัวแปรที่เรียกว่าline:

for path in $line;do echo $path;done

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


ฉันลองสิ่งนี้ในระบบ Ubuntu ของฉันก่อนที่ฉันจะโพสต์คำถามนี้และไม่สามารถใช้งานได้
laconbass

0
echo word1 word2 ... | sed -e 'y/ /\n/;P;D'

เป็นอีกวิธีหนึ่งในการเปลี่ยนคำที่เว้นวรรคหนึ่งให้เป็นคำขึ้นบรรทัดใหม่


-1

สคริปต์ต่อไปนี้เข้าใจง่ายและใช้งานง่าย

cat filename | tr ' ' '\n' | tee filename

2
สาระสำคัญของคำตอบของคุณ ( tr) เหมือนกับคำตอบที่ยอมรับ นอกเหนือจากที่คำตอบของคุณมีปัญหาดังต่อไปนี้: a) คำสั่งไม่ได้ถูกเยื้องกับ 4 ช่องว่าง (-> รูปแบบ markdown) b) การใช้งานของคุณcatไม่มีประโยชน์ (คุณสามารถแทนที่ด้วย< filename tr ' ' '\n') c) ชื่อไฟล์ที่ส่งออกของคุณเหมือนกับชื่อไฟล์อินพุต เมื่อคุณสร้างการแข่งขันข้อมูล
maxschlepzig

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