Bash脚本删除第一个字母

3
我有一个 bash 脚本,用来迁移一些 IMAP 邮件账户,读取自配置文件。
对于单行条目,它可以正常工作,但是当我有多个账户时,只有第一个条目会起作用,其余的则因某种原因在用户名的开头删除了第一个字符。另外,我用于暂停并等待按键的命令也没有起到暂停的作用。(我可以调试这部分,但如果不必的话我一定会给你点赞!)
我 99% 确信我的问题在于我不完全理解的那一行代码:
CREDS=(${VAR// / })

值得注意的是,密码中充斥着特殊字符但没有空格。代码如下:
#! /bin/bash
# Script to help migrate email account contents
# must have accounts all ready set up and using IMAP
# uses hardcoded dovecot master user on host2 too bad host1 is stupid courier

# uses file mailusers.cfg for users and passwords
# one entry per line - format is:
# username@domain.com passwordstring

while read p; do
  VAR=$p
  CREDS=(${VAR// / })
  VARUSER=${CREDS[0]}
  VARPASS=${CREDS[1]}
  OUTPUT="Username: $VARUSER Password: $VARPASS"
  echo $OUTPUT
  imapsync --host1 123.456.789.123 --user1 $VARUSER --password1 $VARPASS --authmech1 PLAIN --host2 999.888.777.123 --user2 $VARUSER*masteruser@mydomain.com --password2 notreallypasswordXD --authmech2 PLAIN --exclude 'Trash|Spam'
  echo "Done!"
  echo
  read -n 1 -s
done < mailusers.cfg

注意:不应该在其他用户已登录的系统上运行此脚本,因为如果他们运行ps aux命令,则可以看到用户名/密码。请参阅imapsync文档以了解更多详细信息。

看起来你正在使用正则表达式分离输入,请尝试 ${^VAR// / }。在正则表达式中,插入符号表示行的开头,除非它在 [] 中。 - sparks
2个回答

3
你错失用户名的第一个字符的原因和你的暂停不起作用的原因完全相同:你的暂停(read -n 1 -p)从 stdin 读取一个字符。然而,stdin 已被重定向到数据文件,所以它读取了用户名的第一个字符。
你真的需要在扩展中引用变量。养成这样做的习惯是非常安全的。
我也不知道替换行的作用:按照你的描述,它看起来像一个无操作,但我想其中一个空格可能是制表符。无论如何,这是不必要的。你可以像这样使用 shell 变量替换所有这些傻傻的操作:
while read -r VARUSER VARPASS ignore_rest_of_line; do
  echo "Username: $VARUSER Password: $VARPASS"
  imapsync --host1 123.456.789.123 --user1 "$VARUSER" \
           --password1 "$VARPASS" --authmech1 PLAIN \
           --host2 999.888.777.123 \
           --user2 "$VARUSER*masteruser@mydomain.com" \
           --password2 notreallypasswordXD \
           --authmech2 PLAIN --exclude 'Trash|Spam'
  echo "Done!"
  echo
  read -n 1 -s < /dev/tty
done < mailusers.cfg

3
编辑并批准对那段代码的修改的人:请不要删除我的反斜杠。它们需要用来表示该行代码被延续。 - rici
顺便提一下,如果你怀疑配置文件中可能有带有尾随垃圾的行,你可以使用:while read VARUSER VARPASS ignore_rest_of_line; do。我没有使用 -r(通常我会用 read),以防你需要在密码中反斜杠转义字符。这取决于你如何处理配置文件中的特殊字符。 - rici
非常好的解释,谢谢。我会测试一下,一旦它能够正常工作,就会接受你的答案。 - Syntax Error
配置文件中没有任何转义。密码只是以纯文本形式粘贴进去的。它们包含反斜杠和其他奇怪的字符,我会遇到更多问题吗? - Syntax Error
@语法错误:是的,你会。如果你不想让反斜杠被解释,请使用read -r。我已经将两个建议都放入答案中。 - rici
现在这个工作完美地运行了。再次感谢,这个任务变得如此简单和快速 :) - Syntax Error

0

正如所指出的,您可以将输入read -n 1 -s重定向到/dev/tty,但另一种方法是为您的输入文件使用不同的文件描述符:

while read -u 4 p; do
  VAR=$p
  CREDS=(${VAR// / })
  VARUSER=${CREDS[0]}
  VARPASS=${CREDS[1]}
  OUTPUT="Username: $VARUSER Password: $VARPASS"
  echo $OUTPUT
  imapsync --host1 123.456.789.123 --user1 $VARUSER --password1 $VARPASS --authmech1 PLAIN --host2 999.888.777.123 --user2 $VARUSER*masteruser@mydomain.com --password2 notreallypasswordXD --authmech2 PLAIN --exclude 'Trash|Spam'
  echo "Done!"
  echo
  read -n 1 -s
done 4< mailusers.cfg

我认为这一行

  CREDS=(${VAR// / })

没有任何不同

  CREDS=($VAR)

并且也更好地实现了

  read -ra CREDS <<< "$VAR"

因为它可以防止路径名扩展。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接