Làm thế nào để tìm chỉ mục của một từ trong chuỗi trong bash?


10

Trong tập lệnh bash,

Tôi có một chuỗi chứa một vài từ được phân tách bằng một hoặc nhiều khoảng trắng. I E:

Name   Age Sex  ID         Address

Nếu tôi muốn tìm bất kỳ từ nào, ví dụ tôi muốn tìm chỉ mục của từ "Tuổi", làm thế nào tôi có thể làm điều đó?

Có lệnh nào sẽ trả về số chỉ mục của từ tôi muốn trực tiếp không?

Cảm ơn.


Liệu các giải pháp phải được nghiêm ngặt trong bash? Hoặc có thể sử dụng awk, grep, vv?
jftuga

Câu trả lời:


12

Bash tự thực hiện việc tách từ trong chuỗi - thực tế, thường xuyên hơn không, tránh đó là một vấn đề và lý do trích dẫn là rất quan trọng. Thật dễ dàng để tận dụng điều đó trong trường hợp của bạn: chỉ cần đặt chuỗi của bạn vào một mảng mà không trích dẫn nó - bash sẽ sử dụng phân tách từ để tách các thành phần riêng lẻ. Giả sử chuỗi của bạn được lưu trữ trong biến $str,

ar=($str) # no quotes!

sẽ trả về một mảng gồm 5 phần tử. Chỉ mục mảng của bạn là chỉ mục từ của bạn (đếm từ 0, giống như trong hầu hết các ngôn ngữ lập trình và ngôn ngữ lập trình), tức là Thời đại Thời gian được truy cập bằng cách sử dụng

${ar[1]}  # 0 => Name, 1 => Age, 2 => Sex, 3 => ID, 4 => Address

hoặc, nếu bạn cần tìm chỉ mục phần tử theo nội dung, lặp qua mảng, tức là

function el_index {
    cnt=0; for el in "${ar[@]}"; do
        [[ $el == "$1" ]] && echo $cnt && break
        ((++cnt))
    done
}
el_index "Age" # => 1

wow ... tôi không biết rằng nếu không có dấu ngoặc kép thì nó sẽ là một mảng. cảm ơn!
G3Y

4
$ export FOO="Name   Age Sex  ID         Address"

Thay thế * Tuổi bằng Tuổi - việc này sẽ xóa mọi thứ trước "Tuổi":

$ echo ${FOO/*Age/Age}
Age Sex ID Address

Nhận bất cứ điều gì trước "Tuổi"

$ echo ${FOO/Age*/}
Name

Lấy độ dài của chuỗi đó (là chỉ số của "Tuổi"):

$ BEGIN=${FOO/Age*/}
$ echo ${#BEGIN}
7

Không trả lời câu hỏi, nhưng wow! Thủ thuật khéo léo. Nó thậm chí hoạt động trong tro và với các biến được nhúng: export L='debug info warn error'; export GTE='warn'; echo ${L/*${GTE}/${GTE}}in 'cảnh báo lỗi'
Steve Tarver

0

Nếu bạn không phải sử dụng bash một cách nghiêm ngặt, nhưng có thể sử dụng các chương trình khác thường thấy trên các hệ thống có bash thì bạn có thể sử dụng một cái gì đó như thế này:

echo "Name   Age Sex ID  Addr" | python -c 'print(raw_input().index("Age"))+1'

Python bắt đầu lập chỉ mục chuỗi của nó ở mức 0, do đó tôi đã thêm +1 vào cuối lệnh.


0

Bạn có thể sử dụng regex bản địa của bash

# a function to print the index of a field and its name
printIx() { 
  for ((l=0,i=1;i<$1;i++)) ;do 
     ((l+=${#BASH_REMATCH[i]}))
  done
  printf '%3s %s\n' $l "$2"
}

#   Using a zero based index
#   "0----+----1----+----2----+----3----+----4"
str="  Name   Age Sex  ID         Address   "

if [[ $str =~ ^(\ *)(Name)(\ +)(Age)(\ +)(Sex)(\ +()ID)(\ +)(Address)\ *$ ]] ;then
  F=(Name Age Sex ID Address)
  f=(   2   4   6  8      10)  # regex back-references
  for ((g=0;g<${#f[@]};g++)) ;do
     printIx  ${f[g]} "${F[g]}"
  done 
fi

Đầu ra

  2 Name
  9 Age
 13 Sex
 20 ID
 29 Address

0

Lưu ý : Giả sử ở đây là theo chỉ mục, bạn có nghĩa là bạn muốn biết từ đó là gì (bắt đầu từ 0), chứ không phải ký tự nào trong chuỗi mà từ đó bắt đầu. Các câu trả lời khác giải quyết sau.

Không phải tôi biết, nhưng bạn có thể làm cho một. Hai thủ thuật:

  1. Sử dụng các khả năng bẩm sinh của cấu trúc for để phân tách một đầu vào không được trích dẫn bởi khoảng trắng.
  2. Xử lý trường hợp bạn không thể tìm thấy cột bạn muốn. Trong trường hợp này, tôi đã chọn gửi chỉ mục tìm thấy đến stout và để mã trạng thái cho biết liệu tìm kiếm có thành công hay không. Có những khả năng khác.

Mã số:

#!/bin/bash
find_index() {
    local str=$1
    local search=$2
    let local n=0
    local retval=1 # here, 1 is failure, 0 success
    for col in $str; do # $str unquoted -> whitespace tokenization!
    if [ $col = $search ]; then
        echo $n
        retval=0
        break
    else
        ((n++))
    fi
    done
    return $retval
}

test="Name   Age Sex  ID         Address"
idx=`find_index "$test" Age`
if [ $? -ne 0 ]; then
    echo "Not found!"
else
    echo "Found: $idx"
fi

0

Hãy thử oneliner javascript sau trong shell (sử dụng shell javascript):

$ js <<< "x = 'Name   Age Sex  ID         Address'; print(x.indexOf('Age'));"
7

Hoặc với tài liệu ở đây:

js <<EOF
x = 'Name   Age Sex  ID         Address';
print(x.indexOf('Age'));
EOF

0

Tôi tìm thấy một giải pháp hoạt động tốt.

$ string = 'bây giờ là thời gian'
$ buf = the $ {string # * the}
$ echo $ buf
output: time
$ index = $ (($ {# string} - $ {# buf} + 1))
$ echo $ index
output: 8 -> index của từ đầu tiên "the"

Nó hoạt động tương tự như hàm indexOf () trong Java, trả về lần xuất hiện đầu tiên của chuỗi đầu vào.

Tìm thấy giải pháp này tại đây http://www.linuxquestions.org/questions/linux-newbie-8/bash-opes-manipulation-help-670627/ (bài cuối). Anh chàng này đã cứu ngày của tôi. Tín cho anh.

Cách nhanh hơn nếu bạn muốn thực hiện chuỗi con từ indexof đầu tiên.

$ a = "một số chuỗi dài"
$ b = "ri"
$ echo $ {a / * $ b / $ b}
ring
$ echo $ {a / $ b * / $ b}
một số cú đánh dài

/programming/10349102/shell-script-subopes-from-first-indexof-subopes


0

Nếu coreutils có sẵn, bạn có thể làm theo cách sau:

tiếng vang $ {str / Tuổi //} | cắt -d / -f1 | wc -w

Theo yêu cầu của MariusMatutiae Tôi đang thêm một lời giải thích về cách hoạt động của 3 bước này:

echo $ {str / Age //} 1. thay thế chuỗi đang được tìm kiếm char duy nhất (trong trường hợp của tôi /)

cut -d / -f1 2. cắt toàn bộ phần chuỗi sau char duy nhất

wc -w 3. đếm và in các từ còn lại này sẽ cung cấp cho chúng tôi một số chỉ mục

Để tham khảo xin vui lòng kiểm tra:

http://www.tldp.org/LDP/abs/html/parameter-substlation.html (đi tới: "Mở rộng biến / thay thế chuỗi con")
http://www.gnu.org/software/coreutils/manual/coreutils .html (đi tới: "Lệnh cắt" và "lệnh gọi wc"


Trong khi điều này giải quyết vấn đề trong tầm tay, những câu trả lời ngắn gọn như vậy được tán thành trong các trang web này. Sẽ hữu ích hơn khi dành một vài từ giải thích chính xác lý do tại sao điều này hoạt động. Xin hãy làm như vậy.
MariusMatutiae

0

Một kết hợp của hai câu trả lời được đưa ra trước đó, sử dụng mảng bash thuần túy và thay thế chuỗi con.

Ý tưởng là lấy một chuỗi tất cả các từ trước từ bạn muốn, sau đó đếm số lượng từ trong chuỗi con đó bằng cách biến nó thành một mảng.

$ haystack="Name   Age Sex  ID         Address"
$ words_before=( ${haystack%Age*} )     # truncate string, make array
$ echo ${#words_before[*]}              # count words in array
1

Tất nhiên Tuổi có thể được lưu trữ trong một biến khác needle, sau đó sử dụng ${haystack%$needle*}. Mong đợi vấn đề nếu từ bạn tìm kiếm là một tập hợp con của một từ khác, trong trường hợp đó câu trả lời của kopischke vẫn hoạt động.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.