ฉันจะgrep
แท็บ (\ t) ในไฟล์บนแพลตฟอร์ม Unix ได้อย่างไร
ฉันจะgrep
แท็บ (\ t) ในไฟล์บนแพลตฟอร์ม Unix ได้อย่างไร
คำตอบ:
หากใช้ GNU grep คุณสามารถใช้ regexp แบบ Perl ได้:
grep -P '\t' *
-P
ทางเลือก
เคล็ดลับคือการใช้เครื่องหมาย $ ก่อนราคาเดียว นอกจากนี้ยังใช้งานได้กับเครื่องมือตัดและอื่น ๆ
grep $'\t' sample.txt
zsh
ดีเท่าที่ฉันจะบอกได้ คุณสามารถแสดงความคิดเห็นเกี่ยวกับความหมายของ$
สัญลักษณ์นั้นได้อย่างไร
$'\t'' '
คุณสามารถใช้ ตัวอย่างจริงที่แสดงให้เห็นว่าการทำงานยังมีการดวลจุดโทษ (ทุบตีไม่เพียง แต่ที่ไม่ได้โดยเริ่มต้นที่ติดตั้งบน Android) busybox grep -oE '^nodev'$'\t''fuse$' /proc/filesystems
เป็น
ฉันไม่เคยจัดการให้ metacharacter '\ t' ทำงานร่วมกับ grep ได้ อย่างไรก็ตามฉันพบวิธีแก้ไขปัญหาสองวิธี:
<Ctrl-V> <TAB>
(กดปุ่ม Ctrl-V แล้วพิมพ์แท็บ)foo | awk '/\t/'
| awk '/\t/'
ทางออกที่จะทำงานให้เปลือกหอยทุกแพลตฟอร์มและระบบ
awk
ทำงานได้ดีที่นี่ แต่ในการทดสอบบางอย่างในเครื่องของฉันกับไฟล์ขนาดใหญ่มากมันเป็นประมาณ 30% grep -P
ช้ากว่าการใช้ นี่อาจเป็นเรื่องเล็กน้อยและไม่เกี่ยวข้องตามกรณีการใช้งานและawk
อาจดีกว่าสำหรับการอ่านและการพกพา
จากคำตอบนี้ใน Ask Ubuntu:
บอก grep ให้ใช้นิพจน์ทั่วไปตามที่กำหนดโดย Perl (Perl มี
\t
ตามแท็บ):grep -P "\t" <file name>
ใช้อักขระแท็บตัวอักษร:
grep "^V<tab>" <filename>
ใช้
printf
เพื่อพิมพ์อักขระแท็บสำหรับคุณ:grep "$(printf '\t')" <filename>
วิธีหนึ่งคือ (นี่คือกับ Bash)
grep -P '\t'
-P
เปิดใช้การแสดงผลปกติของ Perl ดังนั้น \ t จะทำงาน
ตามที่ผู้ใช้กล่าวว่าผ่อนคลายอาจเป็นข้อมูลเฉพาะของ GNU grep ทางเลือกคือแทรกแท็บอย่างแท้จริงหากเชลล์ตัวแก้ไขหรือเทอร์มินัลอนุญาต
อีกวิธีในการแทรกแท็บอย่างแท้จริงภายในนิพจน์คือการใช้$'\t'
คำพูดที่ไม่ค่อยมีคนรู้จักใน Bash:
grep $'foo\tbar' # matches eg. 'foo<tab>bar'
(โปรดทราบว่าหากคุณกำลังจับคู่สำหรับสตริงคงที่คุณสามารถใช้สิ่งนี้กับโหมด '-F')
บางครั้งการใช้ตัวแปรสามารถทำให้สัญกรณ์อ่านง่ายขึ้นและสามารถจัดการได้มากขึ้น:
tab=$'\t' # `tab=$(printf '\t')` in POSIX
id='[[:digit:]]\+'
name='[[:alpha:]_][[:alnum:]_-]*'
grep "$name$tab$id" # matches eg. `bob2<tab>323`
นี่ไม่ใช่สิ่งที่คุณกำลังมองหา แต่อาจใช้ได้ในกรณีของคุณ
grep '[[:blank:]]'
เทียบเท่ากับ
grep -P '[ \t]'
ดังนั้นมันจะค้นหา Space และ Tab
หมายเหตุมันไม่ได้โฆษณาในของฉันman grep
แต่ยังใช้งานได้
$ man grep | grep blank | ห้องน้ำ 0 0 0
-P
เพิ่มอาร์กิวเมนต์แล้ว
ใช้ echo เพื่อแทรกแท็บสำหรับคุณ grep "$(echo -e \\t)"
โดยทั่วไปมีสองวิธีในการแก้ไข:
( แนะนำ ) ใช้ไวยากรณ์นิพจน์ปกติที่สนับสนุนโดย grep (1) Modern grep (1) รองรับสองรูปแบบของ POSIX 1003.2 ไวยากรณ์ regex: REs พื้นฐาน (ล้าสมัย) และREs สมัยใหม่ ไวยากรณ์ถูกอธิบายในรายละเอียดเกี่ยวกับ re_format (7) และ regex (7) man pages ซึ่งเป็นส่วนหนึ่งของระบบ BSD และ Linux ตามลำดับ grep GNU (1) ยังรองรับ REs ที่เข้ากันได้กับ Perl ซึ่งจัดทำโดยไลบรารี pcre (3)
ในภาษา regex สัญลักษณ์แท็บมักจะถูกเข้ารหัสโดย\t
อะตอม อะตอมได้รับการสนับสนุนโดย BSD ที่ขยายการแสดงออกปกติ ( egrep
, grep -E
บนระบบที่เข้ากันได้กับ BSD), เช่นเดียวกับ REs ที่เข้ากันได้กับ Perl ( pcregrep
, GNU grep -P
)
ทั้งการแสดงออกปกติขั้นพื้นฐานและ REs \t
ลินุกซ์ขยายเห็นได้ชัดว่ามีการสนับสนุนไม่มี โปรดศึกษาหน้ายูทิลิตี UNIX เพื่อทราบว่าภาษา regex รองรับ (ดังนั้นความแตกต่างระหว่าง sed (1), awk (1) และ pcregrep (1) นิพจน์ทั่วไป)
ดังนั้นบน Linux:
$ grep -P '\t' FILE ...
บนระบบ BSD เหมือนกัน:
$ egrep '\t' FILE ...
$ grep -E '\t' FILE ...
ส่งอักขระแท็บเป็นรูปแบบ สิ่งนี้ตรงไปตรงมาเมื่อคุณแก้ไขไฟล์สคริปต์:
# no tabs for Python please!
grep -q ' ' *.py && exit 1
อย่างไรก็ตามเมื่อทำงานในเชลล์แบบโต้ตอบคุณอาจต้องพึ่งพาความสามารถของเชลล์และเทอร์มินัลเพื่อพิมพ์สัญลักษณ์ที่เหมาะสมลงในบรรทัด ในเทอร์มินัลส่วนใหญ่สิ่งนี้สามารถทำได้ผ่านการรวมแป้นCtrl
+ V
ซึ่งสั่งให้เทอร์มินัลรักษาอักขระอินพุตถัดไปตามตัวอักษรอย่างแท้จริง ( V
สำหรับ "คำต่อคำ"):
$ grep '<Ctrl>+<V><TAB>' FILE ...
เชลล์บางตัวอาจให้การสนับสนุนขั้นสูงสำหรับการเรียงพิมพ์คำสั่ง เช่นในคำทุบตี (1) ของรูปแบบ$'string'
ได้รับการปฏิบัติเป็นพิเศษ:
bash$ grep $'\t' FILE ...
โปรดทราบว่าแม้ว่าจะดีในบรรทัดคำสั่งสิ่งนี้อาจสร้างปัญหาความเข้ากันได้เมื่อสคริปต์จะถูกย้ายไปยังแพลตฟอร์มอื่น นอกจากนี้ควรระวังด้วยคำพูดเมื่อใช้พิเศษโปรดปรึกษาทุบตี (1) สำหรับรายละเอียด
สำหรับเชลล์เป้าหมาย (และไม่เพียง แต่) ลักษณะการทำงานเดียวกันอาจเลียนแบบโดยใช้การทดแทนคำสั่งเพิ่มเติมโดย printf (1) เพื่อสร้าง regex ที่เหมาะสม:
$ grep "`printf '\t'`" FILE ...
grep "$(printf '\t')"
ทำงานกับฉันใน Mac OS X
ใช้ gawk ตั้งค่าตัวคั่นฟิลด์เป็นแท็บ (\ t) และตรวจสอบจำนวนฟิลด์ หากมากกว่า 1 แสดงว่ามี / มีแท็บอยู่
awk -F"\t" 'NF>1' file
awk /\t/
เพียงพอสำหรับคำถามของ op
ทางเลือกที่ดีคือใช้ 'sed as grep' (ตามที่อธิบายไว้ในบทช่วยสอนแบบคลาสสิคนี้)
sed -n 's/pattern/&/p' file
ตัวอย่าง (ทำงานใน bash, sh, ksh, csh, .. ):
[~]$ cat testfile
12 3
1 4 abc
xa c
a c\2
1 23
[~]$ sed -n 's/\t/&/p' testfile
xa c
a c\2
[~]$ sed -n 's/\ta\t/&/p' testfile
a c\2
วิธี +1 ที่ทำงานใน ksh, dash ฯลฯ : ใช้ printf เพื่อแทรก TAB:
grep "$(printf 'BEGIN\tEND')" testfile.txt
grep "$(printf '\t')" testfile.txt
คำตอบนั้นง่ายกว่า เขียน grep ของคุณและในเครื่องหมายคำพูดพิมพ์แท็บมันทำงานได้ดีอย่างน้อยใน ksh
grep " " *
ฉันใช้ ksh
grep "[^I]" testfile
การใช้วิธีการ 'sed-as-grep' แต่การแทนที่แท็บด้วยตัวอักษรที่มองเห็นได้ของการตั้งค่าส่วนตัวเป็นวิธีที่ฉันชอบเพราะมันแสดงให้เห็นอย่างชัดเจนว่าไฟล์ใดที่มีข้อมูลที่ร้องขอและวางไว้ในบรรทัด:
sed -n 's/\t/\*\*\*\*/g' file_name
หากคุณต้องการใช้ข้อมูลบรรทัด / ไฟล์หรือตัวเลือก grep อื่น ๆ แต่ยังต้องการเห็นการแทนที่อักขระแท็บที่มองเห็นได้คุณสามารถทำได้โดย
grep -[options] -P '\t' file_name | sed 's/\t/\*\*\*\*/g'
ตัวอย่างเช่น:
$ echo "A\tB\nfoo\tbar" > test
$ grep -inH -P '\t' test | sed 's/\t/\*\*\*\*/g'
test:1:A****B
test:2:foo****bar
แก้ไข: เห็นได้ชัดว่าข้างต้นจะเป็นประโยชน์สำหรับการดูเนื้อหาไฟล์เพื่อค้นหาแท็บ - หากวัตถุประสงค์คือการจัดการแท็บเป็นส่วนหนึ่งของเซสชั่นการเขียนสคริปต์ที่ใหญ่กว่านี้ไม่ได้มีวัตถุประสงค์ที่เป็นประโยชน์ใด ๆ
สิ่งนี้ทำงานได้ดีสำหรับ AIX ฉันกำลังค้นหาบรรทัดที่มีJOINED<\t>ACTIVE
voradmin cluster status | grep JOINED$'\t'ACTIVE
vorudb201 1 MEMBER(g) JOINED ACTIVE
*vorucaf01 2 SECONDARY JOINED ACTIVE
คุณอาจต้องการใช้ grep "$(echo -e '\t')"
ข้อกำหนดเพียงอย่างเดียวคือecho
สามารถตีความเครื่องหมายแบคสแลชได้
วิธีการจำแนกเลขฐานสองทางเลือกเหล่านี้ทำงานได้อย่างสมบูรณ์ และฉันชอบของที่ใช้ awk มากเพราะฉันจำการใช้ไวยากรณ์ด้วยตัวอักษรไบนารีไม่ได้เลย อย่างไรก็ตามมันควรจะเป็นไปได้ที่จะกำหนดค่าตัวแปรเชลล์ในแบบพกพา POSIX (เช่น TAB = echo "@" | tr "\100" "\011"
) แล้วใช้จากที่นั่นทุกที่ในแบบพกพา POSIX; เช่นกัน (เช่นชื่อไฟล์ grep "$ TAB") ในขณะที่โซลูชันนี้ทำงานได้ดีกับ TAB มันจะทำงานได้ดีกว่าตัวอักษรไบนารีอื่น ๆ เมื่อใช้ค่าไบนารีอื่นที่ต้องการในการกำหนด (แทนค่าสำหรับอักขระ TAB เป็น 'tr')
เครื่องหมาย $ '\ t' ที่ระบุในคำตอบอื่น ๆ เป็นแบบเฉพาะเชลล์ - ดูเหมือนว่าจะใช้งานได้กับ bash และ zsh แต่ไม่ใช่แบบทั่วไป
หมายเหตุ: ข้อมูลต่อไปนี้ใช้สำหรับfish
เชลล์และไม่ทำงานในการทุบตี :
ในfish
เชลล์หนึ่งสามารถใช้ unquote \t
ตัวอย่างเช่น:
grep \t foo.txt
หรือสามารถใช้สัญลักษณ์ hex หรือ unicode เช่น:
grep \X09 foo.txt
grep \U0009 foo.txt
(สัญลักษณ์เหล่านี้มีประโยชน์สำหรับตัวละครลึกลับเพิ่มเติม)
เนื่องจากค่าเหล่านี้ต้องไม่ถูกอ้างอิงจึงสามารถรวมค่าที่ยกมาและไม่ได้อ้างอิงโดยการต่อข้อมูล
grep "foo"\t"bar"
คุณสามารถพิมพ์
grep \ t foo
grep '\ t' foo
เพื่อค้นหาอักขระแท็บในไฟล์ foo คุณอาจทำรหัสหลบหนีอื่น ๆ ได้เช่นกัน แต่ฉันเพิ่งทดสอบ \ n แม้ว่าจะค่อนข้างใช้เวลานานและไม่ชัดเจนว่าทำไมคุณต้องการใน zsh คุณยังสามารถพิมพ์อักขระแท็บกลับไปที่จุดเริ่มต้น grep และล้อมรอบแท็บด้วยเครื่องหมายคำพูด
มองหาช่องว่างหลาย ๆ ครั้ง[[: space:]] *
grep [[: space:]] * '.' '.'
จะพบสิ่งนี้:
'แท็บ' ..
นี่คือใบเสนอราคาเดียว (') และไม่ใช่สองเท่า (")
นี่คือวิธีที่คุณทำการต่อข้อมูลแบบ grep = -)
grep "<Ctrl+V><TAB>"
มันทำงาน: (ถ้าเป็นครั้งแรกประเภทgrep "
แล้วกด Ctrl + V คีย์คำสั่งผสมแล้วกดปุ่ม TAB แล้วพิมพ์"
และกด Enter, Voila!)