วิธีการรวมชื่อไฟล์หลายบรรทัดเป็นหนึ่งเดียวด้วยตัวคั่นที่กำหนดเองได้อย่างไร


441

ฉันต้องการที่จะเข้าร่วมผลลัพธ์ของการls -1เป็นหนึ่งบรรทัดและคั่นด้วยสิ่งที่ฉันต้องการ

มีคำสั่ง Linux มาตรฐานที่ฉันสามารถใช้เพื่อให้บรรลุนี้

คำตอบ:


689

คล้ายกับตัวเลือกแรก แต่ไม่ใช้ตัวคั่นต่อท้าย

ls -1 | paste -sd "," -

29
เช่นเดียวกับทราบรุ่นวางฉันพยายามต้องมีอาร์กิวเมนต์ "-" ในตอนท้ายเพื่อบอกให้อ่านจาก STDIN เช่นls -1 | paste -s -d ":" - ไม่แน่ใจว่าเป็นของสากลที่มีการวางทั้งหมดหรือไม่
Andy White

4
คนนี้จะดีกว่าเพราะจะช่วยให้ตัวคั่นที่ว่างเปล่า :)
Yura Purbeev

2
หมายเหตุpasteได้รับ-(เข้ามาตรฐาน) paste (GNU coreutils) 8.22เป็นค่าเริ่มต้นอย่างน้อยในของฉัน
fedorqui 'ดังนั้นหยุดทำร้าย'

1
ฉันเพิ่ง upvoted มันนี่คือและตอนนี้มันมีคะแนนเสียงเท่ากันกับคำตอบที่เลือก นี่คือคำตอบ ไม่มีขอบเขตต่อท้าย
thebugfinder

1
ตัวคั่นที่ว่างเปล่าสามารถระบุได้โดยใช้"\0"ดังนั้นpaste -sd "\0" -ทำงานได้ดีสำหรับฉัน!
Brad Parks

379

แก้ไข : เพียงแค่ " ls -m " หากคุณต้องการให้ตัวคั่นของคุณเป็นจุลภาค

อ๊ะพลังและความเรียบง่าย!

ls -1 | tr '\n' ','

เปลี่ยนเครื่องหมายจุลภาค " , " เป็นสิ่งที่คุณต้องการ โปรดทราบว่าสิ่งนี้รวมถึง "เครื่องหมายจุลภาคต่อท้าย"


46
+1 แต่รุ่นที่ซับซ้อนกว่านี้ควรใช้เวลา \ n แตกต่างกัน
mouviciel

5
หากชื่อไฟล์มี\nอยู่ในนั้นมันจะแทนที่ด้วย
codaddict

3
@ShreevatsaR: เขาหมายถึงการไม่ต่อท้าย "," ฉันเชื่อ อย่างนั้นls -1 | tr "\\n" "," | sed 's/\(.*\),/\1/'
Chris

7
@Chris: คุณsedอาจจะมีประสิทธิภาพมากขึ้นเล็กน้อยด้วยตัวละครที่สิ้นสุด:ls -1 | tr "\\n" "," | sed 's/,$//'; echo ''
pieman72

2
การใช้sedหลังจากtrดูเหมือนว่าจะลบสัญลักษณ์ล่าสุดเท่านั้นดูเหมือนจะไม่สมเหตุสมผล ฉันไปกับls -1 | tr '\n' ',' | head -c -1
reddot

29

สิ่งนี้จะแทนที่เครื่องหมายจุลภาคสุดท้ายด้วยการขึ้นบรรทัดใหม่:

ls -1 | tr '\n' ',' | sed 's/,$/\n/'

ls -m รวมบรรทัดใหม่ที่อักขระที่มีความกว้างหน้าจอ (ตัวอย่างที่ 80)

Bash ส่วนใหญ่ ( lsภายนอกเท่านั้น):

saveIFS=$IFS; IFS=$'\n'
files=($(ls -1))
IFS=,
list=${files[*]}
IFS=$saveIFS

การใช้readarray(aka mapfile) ใน Bash 4:

readarray -t files < <(ls -1)
saveIFS=$IFS
IFS=,
list=${files[*]}
IFS=$saveIFS

ขอบคุณ gniourf_gniourf สำหรับคำแนะนำ


นี่จะไม่ดูแลไฟล์ที่มีช่องว่างสีขาวในชื่อ ลองอันนี้: dir = / tmp / testdir; rm -rf $ dir && mkdir $ dir && cd / $ dir && แตะ "นี่คือไฟล์" this_is_another_file && ls -1 && files = ($ (ls -1)) && รายการ = $ {files [@] /% / ,} && list = $ {list% *,} && echo $ list
เริ่ม

1
@dimir: คำตอบมากมายสำหรับคำถามนี้ประสบปัญหานี้ ฉันได้แก้ไขคำตอบของฉันเพื่ออนุญาตให้ใช้ชื่อไฟล์ที่มีแท็บหรือช่องว่าง แต่ไม่ใช่บรรทัดใหม่
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

เวอร์ชันทุบตีของคุณทนทุกข์ทรมานจากการขยายชื่อพา ธ ด้วย เพื่อสร้างอาร์เรย์จากเส้นโปรดพิจารณาใช้mapfile(ทุบตี≥4) mapfile -t files < <(ls -1)รวม: IFSไม่จำเป็นต้องคุ้นเคยกับ และมันก็สั้นลงเช่นกัน
gniourf_gniourf

และเมื่อคุณมีอาร์เรย์ของคุณคุณสามารถใช้ในการเข้าร่วมฟิลด์:IFS saveIFS=$IFS; IFS=,; list=${files[*]}; IFS=$saveIFSหรือใช้วิธีอื่นถ้าคุณต้องการให้ตัวคั่นมีอักขระมากกว่าหนึ่งตัว
gniourf_gniourf

1
@gniourf_gniourf: ฉันได้รวมคำแนะนำของคุณไว้ในคำตอบแล้ว ขอบคุณ
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

24

ฉันคิดว่าอันนี้ยอดเยี่ยม

ls -1 | awk 'ORS=","'

ORS คือ "ตัวคั่นเร็กคอร์ดเอาต์พุต" ดังนั้นตอนนี้บรรทัดของคุณจะถูกรวมเข้ากับเครื่องหมายจุลภาค


6
นี่ไม่ได้ยกเว้นตัวคั่นต่อท้าย
Derek Mahar

6
สิ่งนี้ยอดเยี่ยมโดยเฉพาะอย่างยิ่งเนื่องจากการจัดการตัวแยกเรคคอร์ดหลายตัวอักษร (เช่น" OR ")
Mat Schaffer

15

การรวมกันของการตั้งค่าIFSและการใช้"$*"สามารถทำสิ่งที่คุณต้องการ ฉันใช้ subshell ดังนั้นฉันจะไม่เข้าไปยุ่งกับ $ IFS ของ shell นี้

(set -- *; IFS=,; echo "$*")

ในการจับเอาตพุต

output=$(set -- *; IFS=,; echo "$*")

2
คุณมีข้อมูลเพิ่มเติมเกี่ยวกับวิธีการsetทำงานบ้างไหม? ดูเหมือนจะเป็นของขึ้นเล็กน้อยสำหรับฉัน การมองตื้นman setก็ไม่ได้ทำให้ฉันมีข้อมูลมากนัก
Ehtesh Choudhury

3
หากคุณให้setอาร์กิวเมนต์จำนวนมาก แต่ไม่มีตัวเลือกมันจะตั้งค่าพารามิเตอร์ตำแหน่ง ($ 1, $ 2, ... ) --มีการป้องกันsetในกรณีที่อาร์กิวเมนต์แรก (หรือชื่อไฟล์ในกรณีนี้) เกิดขึ้นเพื่อเริ่มต้นด้วยเส้นประ ดูรายละเอียดของตัวเลือกใน-- help setฉันค้นหาพารามิเตอร์ตำแหน่งเป็นวิธีที่สะดวกในการจัดการรายการสิ่งต่าง ๆ ฉันสามารถใช้สิ่งนี้กับอาเรย์ได้ด้วยoutput=$( files=(*); IFS=,; echo "${files[*]}" )
เกล็นแจ็คแมน

สิ่งนี้ดีมากเพราะไม่ต้องการดำเนินการโปรแกรมเพิ่มเติมใด ๆ และทำงานกับชื่อไฟล์ที่มีช่องว่างหรือแม้แต่การขึ้นบรรทัดใหม่
Eric

1
@EhteshChoudhury ในฐานะที่จะบอกคุณtype set set is a shell builtinดังนั้นman setจะไม่ช่วย แต่help setจะทำ คำตอบ: "- กำหนดอาร์กิวเมนต์ที่เหลือใด ๆ ให้กับพารามิเตอร์ตำแหน่ง"
Stéphane Gourichon

หลังจากset -- *. การล่าช้าในการขยายตัวของระดับหนึ่งที่คุณอาจได้รับการส่งออกที่ถูกต้องโดยไม่จำเป็นต้องของเปลือกย่อยนี้:* IFS=',' eval echo '"$*"'แน่นอนว่าจะเปลี่ยนพารามิเตอร์ตำแหน่ง
Isaac

13

ไม่แนะนำให้ใช้การแยกวิเคราะห์lsโดยทั่วไปดังนั้นวิธีที่ดีกว่าคือใช้เช่น:find

find . -type f -print0 | tr '\0' ','

หรือโดยการใช้findและpaste:

find . -type f | paste -d, -s

สำหรับการเข้าร่วมทั่วไปหลายบรรทัด (ที่ไม่เกี่ยวข้องกับระบบแฟ้ม) การตรวจสอบ: กระชับและแบบพกพา“เข้าร่วม” บนระบบปฏิบัติการยูนิกซ์บรรทัดคำสั่ง


9

อย่าประดิษฐ์ล้อใหม่

ls -m

มันทำอย่างนั้น


OP ต้องการตัวคั่นใด ๆ ดังนั้นคุณยังต้องการ tr เพื่อแปลงเครื่องหมายจุลภาค นอกจากนี้ยังเพิ่มช่องว่างหลังเครื่องหมายจุลภาคเช่น file1, file2, file3
rob

ดังนั้นการใช้ls -mและtrเพื่อลบช่องว่างหลังจากเครื่องหมายจุลภาคคุณจะทำอย่างไรls -m | tr -d ' '
Andy

2
การใช้ tr จะลบช่องว่างภายในชื่อไฟล์ ดีกว่าที่จะใช้sed 's/, /,/g
เกล็นแจ็

7

แค่ทุบตี

mystring=$(printf "%s|" *)
echo ${mystring%|}

5
มีประสิทธิภาพมากกว่าเล็กน้อยคือใช้ "printf -v mystring"% s | "*" - เพื่อหลีกเลี่ยงทางแยกสำหรับ $ ()
camh

แต่สะดุดตาไม่ได้ต่อท้าย|@camh
Christopher

1
เป็นเพียงแค่bashและ gnu coreutilsprintf
ThorSummoner

@camh แต่printf -vจะใช้ได้เฉพาะใน bash เท่านั้นในขณะที่คำตอบที่นำเสนอใช้ได้กับเชลล์หลายประเภท
Isaac

@ คริสโตเฟอร์ใช่ว่าจะลบการต่อท้าย|โดยมีเงื่อนไขว่าทั้งสองบรรทัดถูกใช้: printf -v mystring "%s|" * ; echo ${mystring%|}.
Isaac

7

คำสั่งนี้สำหรับแฟน ๆ PERL:

ls -1 | perl -l40pe0

นี่คือ 40 เป็นรหัสเลขฐานแปดสำหรับพื้นที่

-p จะประมวลผลทีละบรรทัดและพิมพ์

-l จะดูแลการแทนที่ส่วนท้าย \ n ด้วยอักขระ ascii ที่เราให้

-e เป็นการแจ้ง PERL ที่เรากำลังดำเนินการกับ command line

0 หมายความว่าไม่มีคำสั่งให้ดำเนินการ

perl -e0 เหมือนกับ perl -e ''


6

เพื่อหลีกเลี่ยงความสับสนของบรรทัดใหม่สำหรับ tr เราสามารถเพิ่มแฟล็ก -b ใน ls:

ls -1b | tr '\n' ';'

5

ดูเหมือนว่ามีคำตอบอยู่แล้ว

ถ้าคุณต้องการ a, b, cฟอร์แมตให้ใช้ls -m( คำตอบของ Tulains Córdova )

หรือถ้าคุณต้องการa b cฟอร์แมตให้ใช้ls | xargs( คำตอบของChris Jเวอร์ชันที่แปลแล้ว)

หรือถ้าคุณต้องการตัวคั่นอื่น ๆ|ให้ใช้ls | paste -sd'|'(การประยุกต์ใช้คำตอบของ Artem )


5

เพิ่มด้านบนของคำตอบ majkinetor นี่คือวิธีการลบตัวคั่นต่อท้าย (เนื่องจากฉันยังไม่สามารถแสดงความคิดเห็นภายใต้คำตอบของเขา):

ls -1 | awk 'ORS=","' | head -c -1

เพียงแค่ลบจำนวนไบต์ต่อท้ายที่ตัวคั่นของคุณนับ

ฉันชอบวิธีนี้เพราะฉันสามารถใช้ตัวคั่นหลายตัว + ประโยชน์อื่น ๆ ของawk:

ls -1 | awk 'ORS=", "' | head -c -2

แก้ไข

ดังที่ Peter สังเกตเห็นการนับจำนวนลบจะไม่ได้รับการสนับสนุนในส่วนหัวของ MacOS รุ่นดั้งเดิม อย่างไรก็ตามเรื่องนี้สามารถแก้ไขได้ง่าย

coreutilsก่อนติดตั้ง "GNU Core Utilities เป็นยูทิลิตี้ไฟล์เชลล์และการจัดการข้อความพื้นฐานของระบบปฏิบัติการ GNU"

brew install coreutils

คำสั่งที่ให้บริการโดย MacOS จะถูกติดตั้งด้วยคำนำหน้า "g" ตัวอย่างเช่นglsเช่น

เมื่อคุณทำสิ่งนี้แล้วคุณสามารถใช้gheadซึ่งมีจำนวนลบไบต์หรือดีกว่าทำนามแฝง:

alias head="ghead"

หมายเหตุ: การนับจำนวนลบนั้นรองรับเฉพาะรุ่นบางรุ่นเท่านั้นดังนั้นจะไม่สามารถใช้งานได้เช่น macos
ปีเตอร์

ขอบคุณสำหรับการชี้ให้เห็นว่า ฉันได้เพิ่มวิธีแก้ปัญหาสำหรับ MacOS
Aleksander Stelmaczonek

4

วิธีที่ใจเย็น ๆ

sed -e ':a; N; $!ba; s/\n/,/g'
  # :a         # label called 'a'
  # N          # append next line into Pattern Space (see info sed)
  # $!ba       # if it's the last line ($) do not (!) jump to (b) label :a (a) - break loop
  # s/\n/,/g   # any substitution you want

หมายเหตุ :

นี่คือเส้นตรงในความซับซ้อนการแทนที่เพียงครั้งเดียวหลังจากที่ทุกบรรทัดถูกผนวกเข้ากับพื้นที่รูปแบบของ sed

@ คำตอบของ AnandRajaseka และคำตอบอื่น ๆ ที่คล้ายกันเช่นที่นี่คือ O (n²) เนื่องจาก sed ต้องทำการแทนที่ทุกครั้งที่มีการต่อบรรทัดใหม่เข้ากับ Pattern Space

เปรียบเทียบ,

seq 1 100000 | sed ':a; N; $!ba; s/\n/,/g' | head -c 80
  # linear, in less than 0.1s
seq 1 100000 | sed ':a; /$/N; s/\n/,/; ta' | head -c 80
  # quadratic, hung

3

หากเวอร์ชัน xargs ของคุณรองรับแฟล็ก -d สิ่งนี้จะทำงานได้

ls  | xargs -d, -L 1 echo

-d เป็นธงตัวคั่น

หากคุณไม่มี -d คุณสามารถลองทำสิ่งต่อไปนี้

ls | xargs -I {} echo {}, | xargs echo

xargs แรกช่วยให้คุณระบุตัวคั่นซึ่งเป็นเครื่องหมายจุลภาคในตัวอย่างนี้


3
-dระบุตัวคั่นอินพุตด้วย GNU xargs ดังนั้นจะไม่ทำงาน ตัวอย่างที่สองแสดงปัญหาเช่นเดียวกับโซลูชันอื่น ๆ ที่นี่ของตัวคั่นหลงทางในตอนท้าย
Thor

3
sed -e :a -e '/$/N; s/\n/\\n/; ta' [filename]

คำอธิบาย:

-e- หมายถึงคำสั่งที่จะดำเนินการ
:a- เป็นเลเบล
/$/N- กำหนดขอบเขตของการจับคู่สำหรับกระแสในปัจจุบันและ (N) สายต่อ
s/\n/\\n/;- แทนที่ EOL ทั้งหมดด้วย\n
ta;- goto label a หากการแข่งขันประสบความสำเร็จ

ที่นำมาจากบล็อกของฉัน



2

ls สร้างเอาต์พุตคอลัมน์หนึ่งเมื่อเชื่อมต่อกับไพพ์ดังนั้น -1ซ้ำซ้อน

ต่อไปนี้เป็นคำตอบสำหรับ perl อื่น ๆ ที่ใช้joinฟังก์ชันbuiltin ซึ่งไม่ปล่อยให้ตัวคั่นต่อท้าย:

ls | perl -F'\n' -0777 -anE 'say join ",", @F'

ความคลุมเครือ -0777ทำให้ Perl อ่านอินพุตทั้งหมดก่อนที่จะเรียกใช้โปรแกรม

ทางเลือก sed ที่ไม่ปล่อยให้ตัวคั่นต่อท้าย

ls | sed '$!s/$/,/' | tr -d '\n'

0

lsมีตัวเลือก-mในการกำหนดเขตเอาท์พุทด้วย", "เครื่องหมายจุลภาคและเว้นวรรค

ls -m | tr -d ' ' | tr ',' ';'

การวางท่อผลลัพธ์นี้trเพื่อลบพื้นที่หรือเครื่องหมายจุลภาคจะอนุญาตให้คุณไพพ์ผลลัพธ์อีกครั้งtrเพื่อแทนที่ตัวคั่น

ในตัวอย่างของฉันฉันแทนที่ตัวคั่น,ด้วยตัวคั่น;

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


0

คุณสามารถใช้ chomp เพื่อรวมหลายบรรทัดในบรรทัดเดียว:

perl -e 'ในขณะที่ (<>) {if (/ \ $ /) {chomp; } print;} 'bad0> test

ใส่เงื่อนไขการแบ่งบรรทัดในถ้า statement.It สามารถเป็นอักขระพิเศษหรือตัวคั่นใด ๆ


0

Perl เวอร์ชันด่วนพร้อมการจัดการสแลชต่อท้าย:

ls -1 | perl -E 'say join ", ", map {chomp; $_} <>'

อธิบาย:

  • Perl - E: รัน Perl ด้วยคุณสมบัติรองรับ (พูด, ... )
  • พูด: พิมพ์โดยส่งคืนผู้ให้บริการ
  • เข้าร่วม ",", ARRAY_HERE: เข้าร่วมอาร์เรย์ด้วย ","
  • แผนที่ {chomp; $ _} ROWS: ลบจากแต่ละบรรทัดที่ผู้ให้บริการส่งคืนและส่งคืนผลลัพธ์
  • <>: stdin แต่ละบรรทัดเป็น ROW โดยมีแผนที่จะสร้างอาเรย์ของแต่ละแถว
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.