Ví dụ, đã cho:
USCAGoleta9311734.5021-120.1287855805
Tôi chỉ muốn giải nén:
US
Ví dụ, đã cho:
USCAGoleta9311734.5021-120.1287855805
Tôi chỉ muốn giải nén:
US
Câu trả lời:
Có lẽ phương pháp hiệu quả nhất, nếu bạn đang sử dụng bash
shell (và bạn dường như, dựa trên nhận xét của bạn), là sử dụng biến thể chuỗi con của mở rộng tham số:
pax> long="USCAGol.blah.blah.blah"
pax> short="${long:0:2}" ; echo "${short}"
US
Đây sẽ short
là hai ký tự đầu tiên của long
. Nếu long
ngắn hơn hai ký tự, short
sẽ giống với nó.
Phương pháp in-shell này thường tốt hơn nếu bạn định thực hiện nó nhiều (như 50.000 lần mỗi báo cáo như bạn đề cập) vì không có chi phí tạo quy trình. Tất cả các giải pháp sử dụng các chương trình bên ngoài sẽ bị ảnh hưởng bởi chi phí đó.
Nếu bạn cũng muốn đảm bảo độ dài tối thiểu , bạn có thể độn nó ra trước bằng những thứ như:
pax> long="A"
pax> tmpstr="${long}.."
pax> short="${tmpstr:0:2}" ; echo "${short}"
A.
Điều này sẽ đảm bảo rằng bất kỳ thứ gì có độ dài ít hơn hai ký tự đều được đệm vào bên phải bằng dấu chấm (hoặc thứ gì khác, chỉ bằng cách thay đổi ký tự được sử dụng khi tạo tmpstr
). Không rõ là bạn cần cái này nhưng tôi nghĩ tôi đã đưa nó vào cho hoàn chỉnh.
Phải nói rằng, có bất kỳ cách nào để thực hiện việc này với các chương trình bên ngoài (chẳng hạn như nếu bạn không có bash
sẵn cho bạn), một số trong số đó là:
short=$(echo "${long}" | cut -c1-2)
short=$(echo "${long}" | head -c2)
short=$(echo "${long}" | awk '{print substr ($0, 0, 2)}'
short=$(echo "${long}" | sed 's/^\(..\).*/\1/')
Hai ( cut
và head
) đầu tiên giống hệt nhau đối với một chuỗi một dòng - về cơ bản cả hai đều chỉ trả lại cho bạn hai ký tự đầu tiên. Chúng khác nhau ở chỗ cut
sẽ cung cấp cho bạn hai ký tự đầu tiên của mỗi dòng vàhead
sẽ cung cấp cho bạn hai ký tự đầu tiên của toàn bộ dữ liệu đầu vào
Cái thứ ba sử dụng awk
hàm chuỗi con để trích xuất hai ký tự đầu tiên và cái thứ tư sử dụng sed
các nhóm bắt (sử dụng ()
và \1
) để nắm bắt hai ký tự đầu tiên và thay thế toàn bộ dòng bằng chúng. Cả hai đều tương tự như cut
- chúng cung cấp hai ký tự đầu tiên của mỗi dòng trong đầu vào.
Điều đó không quan trọng nếu bạn chắc chắn đầu vào của mình là một dòng duy nhất, tất cả chúng đều có tác dụng giống nhau.
printf '%s'
thay vì echo
trong trường hợp có ký tự lạ trong chuỗi: stackoverflow.com/a/40423558/895245 Đối với POSIX bị ám ảnh: head -c
không phải là POSIX, cut -c
và awk substr
là, sed \1
không chắc chắn.
cách dễ nhất là
${string:position:length}
Nơi này trích xuất $length
chuỗi con từ $string
tại$position
.
Đây là một nội trang bash nên không bắt buộc phải có awk hoặc sed.
Bạn đã nhận được nhiều câu trả lời tốt và tôi muốn đi với Bash BUILTIN bản thân mình, nhưng kể từ khi bạn được hỏi về sed
và awk
và ( hầu như ) không ai khác cung cấp các giải pháp dựa trên họ, tôi cung cấp cho bạn những:
echo "USCAGoleta9311734.5021-120.1287855805" | awk '{print substr($0,0,2)}'
và
echo "USCAGoleta9311734.5021-120.1287855805" | sed 's/\(^..\).*/\1/'
Một awk
trong những lẽ ra phải khá rõ ràng, nhưng đây là lời giải thích về sed
một trong những:
substr($0,1,2)
.
Nếu bạn tham gia bash
, bạn có thể nói:
bash-3.2$ var=abcd
bash-3.2$ echo ${var:0:2}
ab
Đây có thể là những gì bạn cần…
Chỉ cần grep:
echo 'abcdef' | grep -Po "^.." # ab
-P
tùy chọn để làm cho nó ngắn hơn. Tất cả các regex sẽ hiểu mô hình đó.
Bạn có thể sử dụng printf
:
$ original='USCAGoleta9311734.5021-120.1287855805'
$ printf '%-.2s' "$original"
US
Thực sự khá muộn nhưng nó đây rồi
sed 's/.//3g'
Hoặc là
awk NF=1 FPAT=..
Hoặc là
perl -pe '$_=unpack a2'
Nếu bạn muốn sử dụng shell scripting và không dựa vào phần mở rộng không phải posix (chẳng hạn như cái gọi là bashisms), bạn có thể sử dụng các kỹ thuật không yêu cầu các công cụ bên ngoài như grep, sed, cut, awk, v.v., sau đó làm cho tập lệnh của bạn kém hiệu quả hơn. Có thể hiệu quả và tính di động posix không quan trọng trong trường hợp sử dụng của bạn. Nhưng trong trường hợp đó là (hoặc chỉ là một thói quen tốt), bạn có thể sử dụng phương thức tùy chọn mở rộng tham số sau để trích xuất hai ký tự đầu tiên của một biến shell:
$ sh -c 'var=abcde; echo "${var%${var#??}}"'
ab
Điều này sử dụng mở rộng tham số "tiền tố nhỏ nhất" để xóa hai ký tự đầu tiên (đây là ${var#??}
phần), sau đó mở rộng tham số "hậu tố nhỏ nhất" ( ${var%
phần) để xóa chuỗi tất cả trừ hai ký tự đầu tiên khỏi chuỗi gốc giá trị.
Phương pháp này trước đây đã được mô tả trong câu trả lời này cho câu hỏi "Shell = Kiểm tra xem biến có bắt đầu bằng # hay không". Câu trả lời đó cũng mô tả một vài phương pháp mở rộng tham số tương tự có thể được sử dụng trong ngữ cảnh hơi khác với ngữ cảnh áp dụng cho câu hỏi ban đầu ở đây.
Nếu hệ thống của bạn đang sử dụng một shell khác (không phải bash
), nhưng hệ thống của bạn có bash
, thì bạn vẫn có thể sử dụng thao tác chuỗi vốn có của bash
bằng cách gọi bash
với một biến:
strEcho='echo ${str:0:2}' # '${str:2}' if you want to skip the first two characters and keep the rest
bash -c "str=\"$strFull\";$strEcho;"
bash
nếu bạn chưa sử dụng nó.
Chỉ vì mục đích giải trí Tôi thêm một vài điều rằng, mặc dù chúng quá phức tạp và vô dụng, chúng đã không được đề cập:
head -c 2 <( echo 'USCAGoleta9311734.5021-120.1287855805')
echo 'USCAGoleta9311734.5021-120.1287855805' | dd bs=2 count=1 status=none
sed -e 's/^\(.\{2\}\).*/\1/;' <( echo 'USCAGoleta9311734.5021-120.1287855805')
cut -c 1-2 <( echo 'USCAGoleta9311734.5021-120.1287855805')
python -c "print(r'USCAGoleta9311734.5021-120.1287855805'[0:2])"
ruby -e 'puts "USCAGoleta9311734.5021-120.1287855805"[0..1]'
nếu mystring = USCAGoleta9311734.5021-120.1287855805
print substr(mystring,0,2)
sẽ in US
trong đó 0 là vị trí bắt đầu và 2 là cách đọc các ký tự meny
awk
. Xin lỗi, tôi không thể nói lúc đầu.
Đây có phải là những gì bạn muốn?
my $string = 'USCAGoleta9311734.5021-120.1287855805';
my $first_two_chars = substr $string, 0, 2;
ref: substr
perl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'