รับอักขระ X ตัวแรกจากคำสั่ง cat?


41

ฉันมีไฟล์ข้อความที่ฉันส่งออกไปยังตัวแปรในเชลล์สคริปต์ของฉัน ฉันต้องการแค่ 50 ตัวอักษรแรกเท่านั้น

ฉันลองใช้แล้วcat ${filename} cut -c1-50แต่ได้รับมากกว่า 50 ตัวแรก? อาจเกิดจากการcutมองหาบรรทัด (ไม่แน่ใจ 100%) ในขณะที่ไฟล์ข้อความนี้อาจเป็นหนึ่งในสตริงยาว - มันขึ้นอยู่กับ

มียูทิลิตี้ภายนอกที่ฉันสามารถใช้เพื่อรับอักขระ X ตัวแรกจากcatคำสั่งหรือไม่?


10
คุณลืม|? cat ${filename} | cut -c1-50
DisplayName

@DisplayName ได้รับการแก้ไขแล้วขอบคุณที่รับข้อผิดพลาดในการพิมพ์ซ้ำ
jkj2000

1
@ jkj2000 ฉันได้เปลี่ยนกลับไปเป็นเวอร์ชั่นเก่ากว่าซึ่งเป็นคำถามเดิม
Ramesh

คำตอบ:


61
head -c 50 file

สิ่งนี้จะคืนค่า 50 ไบต์แรก

โปรดทราบว่าคำสั่งนั้นไม่ได้นำมาใช้เหมือนกันในทุกระบบปฏิบัติการ บน Linux และ macOS มันทำงานในลักษณะนี้ บน Solaris (11) คุณต้องใช้รุ่น gnu ใน / usr / gnu / bin /


หัวไม่มี-cตัวเลือก ฉันจะไปที่dd (1)แทน
mirabilos

6
โปรดทราบว่าคำตอบนี้ถือว่าไฟล์นั้นมีอักขระ ASCII เท่านั้นเนื่องจาก OP ขอให้มีอักขระ X ตัวแรกไม่ใช่ไบต์
Calimo

2
@mirabilos มันอาจจะไม่สามารถพกพาได้ แต่รุ่นของฉัน ( GNU coreutils 5.97) ทำ
Yossarian

1
POSIX ไม่ได้กำหนด-cเป็นตัวเลือกที่ถูกต้องอย่างไรก็ตามมันขึ้นอยู่กับสภาพแวดล้อมในท้องถิ่นของคุณ unix.com/man-page/posix/1/head
Jules

1
@ Calimo ใช่ฉันรู้ แต่ฉันพยายามสร้างไฟล์ข้อความที่มี 100 ตัวอักษรจากนั้นเรียกใช้คำสั่งของฉันและพิมพ์ 50 อักขระ แต่คุณถูกต้องเกี่ยวกับ ASCII แต่เนื่องจาก OP ตั้งค่าสถานะนี้ตามคำตอบว่าไม่มีกรณีของเขา
DisplayName

27

cutคำสั่งของคุณใช้งานได้หากคุณใช้ไพพ์เพื่อส่งผ่านข้อมูล:

cat ${file} | cut -c1-50 

หรือหลีกเลี่ยงการใช้แมวที่ไร้ประโยชน์และทำให้ปลอดภัยขึ้นเล็กน้อย:

cut -c1-50 < "$file"

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


8
dd status=none bs=1 count=50 if=${filename}

สิ่งนี้จะคืนค่า 50 ไบต์แรก


ววไม่มีstatus=noneธง ใช้2>/dev/nullแทน (และพูดอย่างถูกต้อง): dd if="$filename" bs=1 count=50 2>/dev/null(ถึงแม้จะเป็นเช่นนั้นให้ลองใช้bs=50 count=1เพื่อลดจำนวน syscalls ที่เกี่ยวข้อง)
mirabilos

1
@mirabilos dd มีstatus=noneเมื่อใช้ Ubuntu 14.04, coreutils 8.21 แต่คุณถูกต้องที่จะใช้2>/dev/nullถ้าใช้รุ่นก่อนหน้า
doneal24

1
@ mirabilos distros Linux ส่วนใหญ่ใช้ GNU coreutils เช่นเดียวกับ FreeBSD และ BSD อื่น ๆ มันมีอยู่ใน Solaris เป็นแพ็คเกจ gnu-coreutils ใช่นี่คือ "Unix & Linux" และทั้งระบบ Unix และ Linux ใช้ GNU coreutils
doneal24

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

1
พูดอย่างเคร่งครัดนั่นจะทำหนึ่งread()ใน 50 ไบต์ ถ้าfileเป็นไพพ์เช่นและน้อยกว่าตัวละครที่มีอยู่ในเวลานั้นไบต์น้อยจะถูกส่งกลับ จะมีเทียบเท่าของคุณจะต้องใช้เฉพาะhead -c50 GNU iflag=fullblock
Stéphane Chazelas

4

คำตอบส่วนใหญ่จนถึงตอนนี้สมมติว่าอักขระ 1 ไบต์ = 1 ซึ่งอาจไม่ใช่กรณีนี้หากคุณใช้โลแคลที่ไม่ใช่ ASCII

วิธีที่แข็งแกร่งกว่าเล็กน้อยในการทำ:

testString=$(head -c 200 < "${filename}") &&
  printf '%s\n' "${testString:0:50}"

โปรดทราบว่าสิ่งนี้ถือว่า:

  1. คุณกำลังใช้ksh93, bash(หรือเมื่อเร็ว ๆ นี้zshหรือmksh(แม้เพียง charset หลายไบต์การสนับสนุนจากการmkshเป็น UTF-8 และหลังจากset -o utf8-mode)) และรุ่นของheadการสนับสนุนที่-c(ส่วนใหญ่ทำในปัจจุบัน แต่ไม่ได้มาตรฐานอย่างเคร่งครัด)
  2. สถานที่ปัจจุบันถูกตั้งค่าการเข้ารหัสเช่นเดียวกับไฟล์ (ประเภทlocale charmapและfile -- "$filename"เพื่อตรวจสอบว่า); ถ้าไม่ตั้งค่าด้วยเช่น LC_ALL=en_US.UTF-8)
  3. ฉันใช้ขนาด 200 ไบต์แรกของไฟล์โดยheadสมมติว่าเป็นกรณีที่เลวร้ายที่สุด UTF-8 ซึ่งอักขระทั้งหมดจะถูกเข้ารหัสที่มากที่สุด 4 ไบต์ นี่ควรจะครอบคลุมกรณีส่วนใหญ่ที่ฉันสามารถคิดได้

แน่นอนว่านี่จะถือว่า GNU headหรือการใช้งานอื่นซึ่งเพิ่ม-cตัวเลือกมาตรฐานnōn แต่คุณต้องการ GNU ทุบตีแล้ว (หมายเหตุ: mkshโหมด UTF-8 ของสามารถทำสิ่งนี้สำหรับไฟล์ที่เข้ารหัส UTF-8) ฉันจะถาม OP ถ้าพวกเขาต้องการ octets หรือมัลติไบต์อักขระเพียงแค่ "ตัวอักษร" เป็นคำที่คลุมเครือ / gerneric
mirabilos

ที่ยังถือว่า$filenameหรือไม่ได้มีการขึ้นบรรทัดใหม่ที่ว่างเปล่าหรือสัญลักษณ์หรือเริ่มต้นด้วย$testString -
Stéphane Chazelas

${var:offset:length}สร้างคุณกำลังใช้จริงที่นี่มาจากksh93และยังได้รับการสนับสนุนโดยรุ่นล่าสุดของzsh( zshมีของตัวเอง$testString[1,50]) คุณจำเป็นต้องมี${testString:0:50} ในksh93และzshอย่างไร
Stéphane Chazelas

เพิ่งแก้ไขคำตอบของฉันเพื่อแก้ไขความคิดเห็นข้างต้น
Calimo

2
grep -om1 "^.\{50\}" ${filename}

ตัวแปรอื่น ๆ (สำหรับบรรทัดแรกในไฟล์)

(IFS= read -r line <${filename}; echo ${line:0:50})

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

@mirabilos คุณหมายถึงอะไรภายใต้เครื่องมือระดับสูง : readและecho? หรือbash expansion?
Costas

grep(regexp) และใช่การใช้เชลล์ที่นี่ (คำใบ้: บรรทัดแรกอาจมีขนาดใหญ่) (ที่ถูกกล่าวว่า bashism ยังไม่ได้อยู่ใน POSIX แต่เปลือกหอยส่วนใหญ่ดำเนินการที่.)
mirabilos

0

1. สำหรับไฟล์ ASCII ให้ทำเช่น @DisplayName พูดว่า:

head -c 50 file.txt

จะพิมพ์ไฟล์ 50 ชุดแรกของ file.txt เช่น

2. สำหรับข้อมูลไบนารีใช้hexdumpเพื่อพิมพ์ออกมาเป็นตัวอักษรฐานสิบหก:

hexdump -n 50 -v file.bin

จะพิมพ์ไฟล์ 50 ไบต์แรกของ file.bin เช่น

โปรดทราบว่าหากไม่มี-vตัวเลือก verbose hexdumpจะแทนที่บรรทัดซ้ำด้วยเครื่องหมายดอกจัน ( *) แทน ดูที่นี่: https://superuser.com/questions/494245/what-does-an-asterisk-mean-in-hexdump-output/494613#494613


-2

คุณสามารถใช้สิ่งนี้เพื่อจัดการปัญหาได้อย่างง่ายดาย

sed -e 's/^\(.\{50\}\).*/\1/' yourfile

อยากรู้ว่ามันลดลงได้อย่างไรถ้ามันแก้คำถามของ OP: "ฉันต้องการแค่ 50 ตัวอักษรแรก" สิ่งนี้สำเร็จตามที่ร้องขอโดย UUOC (Useless Use of Cat)
munkeyoto

1
คำตอบนี้ให้ตัวอักษรห้าสิบตัวแรกของแต่ละบรรทัดในไฟล์ไม่ใช่แค่ 50 ตัวแรกของไฟล์ ยังไม่พิมพ์อะไรเลยถ้าทุกบรรทัดมีความยาวน้อยกว่า 50 ตัวอักษร วิธีแก้ปัญหาของคุณจะทำงานได้ดีขึ้นด้วยsed -n -e '1s/^\(.\{50\}\).*/\1/p' ${filename}
doneal24

ความเข้าใจอาจมีเพียง: หัว -n 1 | sed -e 's / ^ (. \ {50 \}). * / \ 1 /' ... และมันจะแก้ไขปัญหาได้ OP ระบุว่า: "ต้องการตัวอักษร 50 ตัวแรกเท่านั้น"
munkeyoto

1
Nope หากบรรทัดแรกมีความยาวเพียง 49 ตัวอักษรจะไม่มีผลใด ๆ
doneal24

ดั๊กฉันเข้าใจสิ่งนี้เป็นครั้งแรกโดยที่ OP ไม่ได้พูดถึงเรื่องการพิมพ์ถ้าเส้นมีน้อยกว่า 50 ตัวอักษรดังนั้นฉันจึงยังไม่เห็นจุดของคุณหรือจุดที่ถูกลดลงเพราะมันตกอยู่ในสิ่งที่จะได้ทำงานด้วย head: head -n 1 $ {filename} | sed -n -e '1s / ^ (. \ {50 \}). * / \ 1 / p'
munkeyoto
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.