Làm thế nào để khẳng định rằng một chuỗi có một ký tự dòng mới và nếu có, hãy loại bỏ nó


9

Tôi có một chuỗi là kết quả của một số hoạt động tôi không kiểm soát được. Khi tôi in biến này bằng cách sử dụng echo, tôi nhận được:

echo $myvar
hello

Tuy nhiên, khi tôi làm

if [ $myvar = "hello" ]; then
    echo they are equal
else
    echo they are not equal
fi

Tôi luôn luôn nhận được rằng họ không bằng nhau. Tôi nghi ngờ điều này là do một newlinenhân vật.

Chuỗi cũng hành xử kỳ lạ. Khi tôi làm:

newVAR="this is my var twice: "$myvar$myvar
echo $newVAR

Tôi có:

hellois my var twice: hello

Làm thế nào tôi có thể kiểm tra nếu điều này thực tế là do một newlinevà, nếu vậy, loại bỏ nó?


1
Trong Bash, bạn có thể có printf '%q\n' "$string"được một phiên bản thoát của bất kỳ chuỗi nào. Ví dụ: printf '%q\n' 'foo\n'-> foo\\n; printf '%q\n' $'foo\n'->$'foo\n'
l0b0

1
Bạn không trích dẫn việc mở rộng bất kỳ biến nào của bạn. Nếu họ có bất kỳ khoảng trắng ở cuối, bạn sẽ không thấy nó với echo $foo. Làm echo "$foo"thay thế.
Peter Cordes

Câu trả lời:


9

Vấn đề là bạn có một Vận chuyển trở lại nhúng (CR, \r). Điều này làm cho điểm chèn văn bản đầu cuối quay trở lại điểm bắt đầu của dòng đang in. Đó là lý do tại sao bạn nhìn thấy 'xin chào' ở đầu dòng trong $newVARví dụ của bạn - sed -n lhiển thị chế độ xem dễ đọc của các ký tự không thể in được (và cuối dòng).

var=ab$'\r'c ; echo "$var";  printf %s "$var" | sed -n l
# output:
cb
ab\rc$

Bạn có thể kiểm tra nó với một kiểm tra điều kiện bash đơn giản:

[[ $var == *$'\r'* ]] && echo yes || echo no
# output:
yes

Bạn có thể kết hợp kiểm tra và sửa chữa trong một bước bằng cách kiểm tra \r(các) và xóa chúng qua:

fix="${var//$'\r'/}"; echo "$var"; echo "$fix"
# output:
cb
abc

Bản sửa lỗi sử dụng mở rộng tham số Shell . Biểu mẫu cụ thể được sử dụng ở trên là để thay thế các chuỗi con dựa trên mẫu được cung cấp của bạn: ${parameter/pattern/string}<- Điều này chỉ thay thế mẫu tìm thấy đầu tiên bằng chuỗi trong biến có tên * tham số. Để thay thế tất cả các mô hình, bạn chỉ cần thay đổi người đầu tiên /đến //.


bạn có thể giải thích chút mã cuối cùng của bạn? các fix="....dòng?
farid99

@ farid99: giải thích được thêm vào để trả lời, Lưu ý fixcó thể là varchính nó - hoặc thường bạn chỉ có thể sử dụng mở rộng tham số như hiện tại mà không cần phải gán lại giá trị đã sửa đổi (có thể) ..
Peter.O

5

Bạn có thể biểu diễn \rnhư $'\r'trong bash:

if [ "$myvar" = "hello"$'\r' ]; then
    echo they are equal
else
    echo they are not equal
fi

Hoặc cắt cuối cùng \rtrong myvar:

if [ "${myvar%$'\r'*}" = "hello" ]; then
    echo they are equal
else
    echo they are not equal
fi

3

Thật kỳ lạ, trong nhiều vỏ getoptslà một ứng cử viên rất có thể cho một công việc như thế này. Điều này thoạt nghe có vẻ trái ngược, nhưng nếu bạn cho rằng getopts'chức năng chính là nhận ra và đưa ra để giải thích như nhiều tùy chọn dòng lệnh được chỉ định như có thể được tìm thấy trong một chuỗi nối liền nhau, thì nó có thể bắt đầu tạo ra một chút Ý nghĩa hơn.

Để chứng minh, từ một bashvỏ:

x=$(printf '\n\r%010s\t' hello)
OPTIND=1
while  getopts : na "-$x"
do     printf %q\\n "$OPTARG"
done

$'\n'
$'\r'
\
\
\
\
\
h
e
l
l
o
$'\t'

Theo cách đó, đôi khi có thể thuận tiện để cho phép getoptsxử lý việc tháo gỡ như một loại tự động điều khiển vỏ cho các trường hợp như thế này. Khi bạn làm như vậy, bạn chỉ có thể sàng lọc các byte không mong muốn casehoặc [kiểm tra ]và xây dựng chuỗi sao lưu của bạn từ byte 1:

OPTIND=1 y=$(printf \\n\\r) z=
while  getopts : na "-$x"
do     case $OPTARG in ([!$y])
            z=$z$OPTARG
       esac
done
printf %q\\n "$z"

$'     hello\t'

Với trường hợp ví dụ đơn giản này - và được cung cấp một vỏ hỗ trợ các mở rộng tham số đã được đề cập ở nơi khác - các mở rộng cho biết có thể sẽ phục vụ bạn tốt hơn ở đây. Nhưng tôi nghĩ getoptscó lẽ cũng đáng được đề cập trong trường hợp bạn không nhận thức được khả năng của nó trong khía cạnh này. Chắc chắn khi tôi biết về nó, tôi đã tìm thấy nhiều ứng dụng hữu ích cho nó.


0

Mặc dù Bash và các ngôn ngữ shell khác rất tiện dụng, đôi khi tốt hơn là sử dụng một ngôn ngữ kịch bản thực sự - như Perl. Perl có thể thay thế các tập lệnh shell gọi các ngôn ngữ khác như sed và awk cũng như các lệnh UNIX khá dễ dàng. Tôi đã học được điều này hơn 20 năm trước khi viết các tập lệnh C-Shell lần lượt được gọi là sed, awk và các lệnh UNIX khác nhau - trước khi gọi mã FORTRAN. Trong Perl tôi sẽ làm:

chomp($myvar);   # removes the newline char

if("$myvar" eq "hello")   # string comparison
  {
  print "they are equal\n";
  }
else
  {
  print "they are not equal\n";
  }
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.