ฉันจะคัดลอกไฟล์ที่ต้องใช้สิทธิ์การเข้าถึงระดับรากด้วย scp อย่างไร


167

ฉันมีเซิร์ฟเวอร์ Ubuntu ที่ฉันเชื่อมต่อโดยใช้ SSH

ฉันจำเป็นต้องอัปโหลดไฟล์จากเครื่องของฉันเป็น/var/www/บนเซิร์ฟเวอร์แฟ้มในเป็นเจ้าของโดย/var/www/root

การใช้ PuTTY หลังจากที่ฉันเข้าสู่ระบบฉันต้องพิมพ์sudo suและรหัสผ่านของฉันก่อนเพื่อที่จะสามารถแก้ไขไฟล์/var/www/ได้

แต่เมื่อฉันกำลังคัดลอกไฟล์โดยใช้ WinSCP ฉันไม่สามารถสร้างสร้าง / แก้ไขไฟล์ได้/var/www/เนื่องจากผู้ใช้ที่ฉันกำลังเชื่อมต่อด้วยไม่มีสิทธิ์ในไฟล์/var/www/และฉันไม่สามารถพูดsudo suอย่างที่ฉันทำในกรณีของเซสชัน ssh .

คุณรู้หรือไม่ว่าฉันสามารถจัดการกับเรื่องนี้ได้อย่างไร

ถ้าฉันกำลังทำงานกับเครื่องท้องถิ่นฉันจะโทรgksudo nautilusแต่ในกรณีนี้ฉันมีเพียงเครื่องที่เข้าถึงเทอร์มินัล


ดูเหมือนว่าจะเป็นคำถามเพิ่มเติมสำหรับผู้ให้บริการเซิร์ฟเวอร์เสมือนของคุณหรือสำหรับผู้พัฒนา putty หรือ winscp
dobey

7
@dobey คุณผิดอย่างไม่น่าเชื่อมันเป็นเรื่องเกี่ยวกับสิทธิ์อูบุนตู!
Dimitris Sapikas

7
ทำไมถึงปิด นี่เป็นคำถามที่ถูกต้องสมบูรณ์เกี่ยวกับการคัดลอกไฟล์ด้วย scp - นักพัฒนาเว็บทุกคนคุ้นเคยกับสถานการณ์นี้
Sergey


ฉันมีปัญหาที่คล้ายกัน ฉันสร้างไฟล์ (HTML ในกรณีนี้) บนคอมพิวเตอร์ Windows และลองคัดลอกกับโฟลเดอร์ WinSCP to / var / www / html / เว็บไซต์ และมันบอกว่ามีปัญหาสิทธิ์ เนื่องจากฉันสามารถคัดลอกไปยังโฟลเดอร์ / home ของฉันฉันได้คัดลอกไฟล์ในสองขั้นตอน แต่มันไม่สะดวก :-) ฉันพยายามเพิ่มผู้ใช้ของฉันในกลุ่ม www-data แต่ไม่ได้ช่วยอะไร ความคิดใดที่ว่าทำไมการเพิ่มผู้ใช้ไปยัง www-data ยังไม่อนุญาตให้ผู้ใช้คัดลอกไฟล์ไปยังโฟลเดอร์ที่กลุ่ม www-data เป็นเจ้าของ?
JanezKranjski

คำตอบ:


125

คุณขวาไม่มีเมื่อทำงานกับsudo scpวิธีแก้ปัญหาคือใช้scpเพื่ออัปโหลดไฟล์ไปยังไดเรกทอรีที่ผู้ใช้ของคุณมีสิทธิ์ในการสร้างไฟล์จากนั้นเข้าสู่ระบบผ่านทาง ssh และใช้sudoเพื่อย้าย / คัดลอกไฟล์ไปยังปลายทางสุดท้าย

scp -r folder/ user@server.tld:/some/folder/you/dont/need/sudo
ssh user@server.tld
 $ sudo mv /some/folder /some/folder/requiring/perms 
# YOU MAY NEED TO CHANGE THE OWNER like:
# sudo chown -R user:user folder

อีกวิธีหนึ่งคือเปลี่ยนสิทธิ์ / ความเป็นเจ้าของไดเรกทอรีที่คุณอัปโหลดไฟล์เป็นดังนั้นผู้ใช้ที่ไม่มีสิทธิ์ของคุณจะสามารถเขียนไปยังไดเรกทอรีเหล่านั้นได้

โดยทั่วไปการทำงานในrootบัญชีควรเป็นข้อยกเว้นไม่ใช่กฎ - วิธีที่คุณใช้ถ้อยคำคำถามของคุณทำให้ฉันคิดว่าบางทีคุณอาจดูถูกดูแคลนซึ่งจะนำไปสู่ปัญหาเกี่ยวกับการอนุญาต - ภายใต้สถานการณ์ปกติที่คุณไม่ต้องการ สิทธิพิเศษระดับผู้ดูแลระบบเพื่อเข้าถึงไฟล์ของคุณเอง

ในทางเทคนิคคุณสามารถกำหนดค่า Ubuntu ให้อนุญาตการเข้าสู่ระบบจากระยะไกลได้โดยตรงrootแต่คุณสมบัตินี้ถูกปิดการใช้งานด้วยเหตุผลบางอย่างดังนั้นฉันจึงขอแนะนำให้คุณทำเช่นนั้น


ฉันไม่ได้รับการแก้ปัญหาแรกคุณช่วยกรุณา spesific litle มากขึ้น?
Dimitris Sapikas

เมื่อฉันพูดไฟล์ของตัวเองฉันหมายถึง / var / www ฉันกำลังใช้ vps ของฉันเป็นเว็บเซิร์ฟเวอร์ .... ในโฟลเดอร์ของฉันเองฉันสามารถเข้าถึงได้อย่างเต็มที่
Dimitris Sapikas

7
เรื่อง ทางออกแรก 1. scp -R mysite dimitris@myserver.com:/home/dimitris/2. ssh dimitris@myserver.com3. sudo mv ~/mysite /var/www- เป็นกระบวนการ 2 ขั้นตอนก่อนอื่นให้คุณscpส่งไฟล์ไปที่บ้านของคุณจากนั้นคุณลงชื่อเข้าใช้ผ่านทาง ssh และคัดลอก / ย้ายไฟล์ไปที่ที่ควรจะเป็น
Sergey

36

วิธีอื่นคือการคัดลอกโดยใช้ tar + ssh แทน scp:

tar -c -C ./my/local/dir \
  | ssh dimitris@myserver.com "sudo tar -x --no-same-owner -C /var/www"

2
นี่เป็นวิธีที่ดีที่สุดที่จะทำ
mttdbrd

2
ฉันไม่สามารถใช้วิธีนี้ในการทำงานได้สำเร็จ sudo: sorry, you must have a tty to run sudoในฐานะที่เป็นลายลักษณ์อักษรที่ฉันได้รับ ถ้าผมเพิ่ม "t-" เพื่อจัดสรร TTY Pseudo-terminal will not be allocated because stdin is not a terminal.แล้วฉันจะได้รับ ฉันไม่เห็นการทำงานนี้หากไม่มีรหัสผ่าน sudo
IBBoard

1
@ กระดาน: ลองวิธีแก้ปัญหาที่นี่โดยใช้ ssh -t:ssh -t dimitris@myserver.com "sudo tar -x --no-same-owner -C /var/www"
Alexander Bird

2
@AlexanderBird ในขณะที่ใช้งานได้ในหลายกรณีฉันไม่แน่ใจว่าจะใช้งานได้ที่นี่เพราะเรากำลังพยายามส่ง tarball ผ่านการเชื่อมต่อ SSH ดูserverfault.com/questions/14389/…
IBBoard

นี่คือสิ่งที่ใช้งานได้ในที่สุดสำหรับฉัน คุณไม่ได้รับอนุญาตให้ไฟล์จากระยะไกลที่คุณต้องการคัดลอกไปยังท้องถิ่นทำsudo tar, เก็บมันเปลี่ยนสิทธิ์ใช้chmodและchownจากนั้นคัดลอกไปยังท้องถิ่น โดยเฉพาะถ้าเป็นไดเรกทอรี
forumulator

27

วิธีที่รวดเร็ว

จากเซิร์ฟเวอร์ไปยังเครื่องท้องถิ่น:

ssh user@server "sudo cat /etc/dir/file" > /home/user/file

จากเครื่องไปยังเซิร์ฟเวอร์:

cat /home/user/file | ssh user@server "sudo tee -a /etc/dir/file"

5
คำตอบนี้ถูกประเมินค่าน้อยเกินไป ง่ายสะอาดอ่านหรือเขียนไฟล์รูทที่มีการทำงานแบบปรมาณูเพียงครั้งเดียวและไม่ต้องการสิ่งใดที่ไม่ได้รับประกันว่าจะอยู่ที่นั่นหากคุณกำลังใช้ scp ข้อเสียเปรียบหลักคือมันไม่ได้คัดลอกสิทธิ์ หากคุณต้องการสิ่งนี้โซลูชัน tar ก็ดีกว่า นี่เป็นเทคนิคที่ทรงพลังโดยเฉพาะอย่างยิ่งถ้ารวมกับ xargs / bash magic เพื่อสำรวจเส้นทาง ..
markgo2k

ฉันคิดว่าคำถามเกี่ยวกับการอัปโหลดไฟล์จากท้องถิ่นสู่ระยะไกลและไม่ใช่ในทางกลับกัน
Korayem

1
ทำอย่างสวยงาม นี่คือสิ่งที่ฉันกำลังมองหาทั้งขึ้นและลง ขอบคุณ
Jeremy

สมควรที่จะได้คำตอบอันดับต้นอย่างแน่นอน
Andrew Watson

สิ่งนี้สามารถทำได้สำหรับไดเรกทอรีแทนไฟล์เช่นกัน?
lucidbrot

26

คุณยังสามารถใช้ansibleเพื่อทำให้สิ่งนี้สำเร็จ

คัดลอกไปยังโฮสต์ระยะไกลโดยใช้โมดูลของ ansiblecopy :

ansible -i HOST, -b -m copy -a "src=SRC_FILEPATH dest=DEST_FILEPATH" all

ดึงข้อมูลจากโฮสต์ระยะไกลโดยใช้โมดูลของ ansiblefetch :

ansible -i HOST, -b -m fetch -a "src=SRC_FILEPATH dest=DEST_FILEPATH flat=yes" all

บันทึก:

  • เครื่องหมายจุลภาคใน-i HOST,ไวยากรณ์ไม่ใช่การพิมพ์ผิด มันเป็นวิธีการใช้งานของ ansible โดยไม่จำเป็นต้องมีไฟล์สินค้าคงคลัง
  • -bทำให้การดำเนินการบนเซิร์ฟเวอร์เป็นรูต -bขยายไป--becomeและค่าเริ่มต้น--become-userคือรูทโดยค่าเริ่มต้น--become-methodคือ sudo
  • flat=yesคัดลอกเฉพาะไฟล์เท่านั้นอย่าคัดลอกเส้นทางระยะไกลทั้งหมดที่นำไปสู่ไฟล์
  • การใช้ไวด์การ์ดในพา ธ ไฟล์ไม่ได้รับการสนับสนุนจากโมดูลที่รองรับเหล่านี้
  • คัดลอกไดเรกทอรีที่จะได้รับการสนับสนุนโดยcopyโมดูล แต่ไม่ได้โดยfetchโมดูล

การร้องขอเฉพาะสำหรับคำถามนี้

นี่คือตัวอย่างที่ระบุและระบุไว้โดยสมบูรณ์สมมติว่าไดเรกทอรีบนโลคัลโฮสต์ของคุณมีไฟล์ที่จะแจกจ่ายคือsourcedirและชื่อโฮสต์ของเป้าหมายระยะไกลคือhostname:

cd sourcedir && \
ansible \
   --inventory-file hostname, \ 
   --become \
   --become-method sudo \
   --become-user root \
   --module-name copy \
   --args "src=. dest=/var/www/" \
   all

ด้วยการร้องขอให้รัดกุม:

cd sourcedir && \
ansible -i hostname, -b -m copy -a "src=. dest=/var/www/" all

ป.ล. ฉันรู้ว่าการพูดว่า "เพิ่งติดตั้งเครื่องมือที่ยอดเยี่ยมนี้" เป็นคำตอบแบบหูหนวก แต่ฉันได้พบเบิ้ลจะเป็นซุปเปอร์ประโยชน์สำหรับการบริหารจัดการเซิร์ฟเวอร์ระยะไกลเพื่อติดตั้งมันก็จะนำคุณประโยชน์อื่น ๆ นอกเหนือจากการปรับใช้ไฟล์


ฉันชอบคำตอบนี้ แต่ฉันขอแนะนำให้คุณนำมันไปที่คำถามที่ถามกับคำอธิบายทั่วไปที่มากขึ้นก่อนการโหวต อะไรทำนองนั้นansible -i "hostname," all -u user --become -m copy -a ...
Mike D

@MikeD: การเปลี่ยนแปลงข้างต้นมีลักษณะอย่างไร
erik.weathers

1
สิ่งที่ต้องการ-i 'host,'เป็นไวยากรณ์ที่ถูกต้อง? ฉันคิดว่ามันง่ายที่จะสูญเสียเครื่องหมายวรรคตอนเช่นนั้นเมื่ออ่านคำสั่ง (สำหรับผู้อ่านฉันหมายถึงถ้าไม่ใช่เชลล์)
mwfearnley

1
@mwfearnley: แน่ใจว่าเชลล์จะรักษา-i 'host,'และเช่นเดียวกับหรือ-i host, -i "host,"โดยทั่วไปฉันต้องการเก็บการเรียกร้องเหล่านี้ให้สั้นที่สุดเท่าที่จะเป็นไปได้เพื่อป้องกันไม่ให้เกิดความหวาดกลัว แต่คุณควรรู้สึกฟรีเพื่อให้มันเป็นคำพูดที่ชัดเจนและชัดเจนตามที่คุณคิดว่าจำเป็นสำหรับความชัดเจน
erik.weathers

2
วิธีไปคิดนอกกรอบ! ใช้งานได้ดีใน
Ansible

12

เมื่อคุณเรียกใช้sudo suไฟล์ใด ๆ ที่คุณสร้างจะเป็นเจ้าของโดยรูท แต่โดยค่าเริ่มต้นแล้วจะไม่สามารถล็อกอินเป็น root ด้วย ssh หรือ scp ได้ นอกจากนี้ยังเป็นไปไม่ได้ที่จะใช้ sudo กับ scp ดังนั้นไฟล์จึงไม่สามารถใช้งานได้ แก้ไขปัญหานี้โดยอ้างสิทธิ์ความเป็นเจ้าของในไฟล์ของคุณ:

สมมติว่าชื่อผู้ใช้ของคุณคือ dimitri คุณสามารถใช้คำสั่งนี้

sudo chown -R dimitri:dimitri /home/dimitri

ต่อจากนั้นตามที่กล่าวไว้ในคำตอบอื่น ๆ วิธี "Ubuntu" คือการใช้ sudo ไม่ใช่การเข้าสู่ระบบรูท มันเป็นกระบวนทัศน์ที่มีประโยชน์พร้อมข้อดีด้านความปลอดภัยที่ยอดเยี่ยม


ฉันใช้วิธีนี้ แต่ถ้าฉันสามารถเข้าถึงระบบไฟล์ของตัวเองได้อย่างเต็มที่ฉันไม่ต้องการพิมพ์sudo chow ...สำหรับทุก ๆ ไดเรกทอรี: S
Dimitris Sapikas

2
การเปลี่ยนความเป็นเจ้าของไฟล์ระบบทั้งหมดให้กับผู้ใช้เพื่อความสะดวกในการส่งผ่านนั้นเป็นสิ่งที่หลีกเลี่ยงไม่ได้ จะช่วยให้ข้อผิดพลาด userspace ใด ๆ ที่คุณอาจพบความปลอดภัยของระบบของคุณ เป็นการดีกว่าที่จะเปลี่ยนความเป็นเจ้าของไฟล์ที่คุณต้องการเปลี่ยนหรืออัปเดตโดย SCP แต่จะปล่อยให้ทุกสิ่งอื่นเป็นของรูท (เช่นควรจะเป็น) ที่กล่าวไว้-Rในchownบอกให้เปลี่ยนความเป็นเจ้าของของไดเรกทอรีนั้นและไฟล์ลูกและไดเรกทอรีทั้งหมดซ้ำ ... เพื่อให้คุณสามารถทำสิ่งที่คุณต้องการ
trognanders

อืม .... ดูเหมือนว่าจะใช้งานได้ดีขอบคุณ! ขอโทษฉันไม่สามารถ upvote (ระบบไม่อนุญาตให้ฉันทำ ... )
Dimitris Sapikas

11

อาจเป็นวิธีที่ดีที่สุดที่จะใช้rsync( Cygwin / cwRsyncใน Windows) ผ่าน SSH?

ตัวอย่างเช่นในการอัปโหลดไฟล์กับเจ้าของwww-data:

rsync -a --rsync-path="sudo -u www-data rsync" path_to_local_data/ login@srv01.example.com:/var/www

ในกรณีของคุณหากคุณต้องการสิทธิ์รูทคำสั่งจะเป็นดังนี้:

rsync -a --rsync-path="sudo rsync" path_to_local_data/ login@srv01.example.com:/var/www

ดู: scp ไปยังเซิร์ฟเวอร์ระยะไกลด้วย sudo


5

หากคุณใช้เครื่องมือ OpenSSH แทนการฉาบคุณสามารถทำได้โดยการเริ่มต้นการถ่ายโอนไฟล์บนเซิร์ฟเวอร์ด้วยscp sudoตรวจสอบให้แน่ใจว่าคุณมีsshdดีมอนทำงานอยู่ในเครื่องของคุณ ด้วยssh -Rคุณสามารถให้เซิร์ฟเวอร์วิธีการติดต่อเครื่องของคุณ

บนเครื่องของคุณ:

ssh -R 11111:localhost:22 REMOTE_USERNAME@SERVERNAME

นอกเหนือจากการเข้าสู่ระบบของคุณในเซิร์ฟเวอร์สิ่งนี้จะส่งต่อการเชื่อมต่อทุกครั้งที่ทำบนพอร์ตของเซิร์ฟเวอร์ 11111 ไปยังพอร์ตของเครื่อง 22: พอร์ตที่คุณsshdกำลังฟังอยู่

บนเซิร์ฟเวอร์ให้เริ่มการถ่ายโอนไฟล์ดังนี้:

cd /var/www/
sudo scp -P 11111 -r LOCAL_USERNAME@localhost:FOLDERNAME .

1

คุณอาจใช้สคริปต์ที่ฉันเขียนโดยได้แรงบันดาลใจจากหัวข้อนี้:

touch /tmp/justtest && scpassudo /tmp/justtest remoteuser@ssh.superserver.com:/tmp/

แต่สิ่งนี้ต้องมีสิ่งที่บ้า (ซึ่ง btw. ทำโดยสคริปต์อัตโนมัติ)

  1. เซิร์ฟเวอร์ที่ไฟล์ถูกส่งไปยังจะไม่ถามรหัสผ่านอีกต่อไปในขณะที่สร้างการเชื่อมต่อ ssh ไปยังคอมพิวเตอร์ต้นทาง
  2. เนื่องจากความจำเป็นในการขาดพรอมต์ sudo บนเซิร์ฟเวอร์ sudo จะไม่ขอรหัสผ่านบนเครื่องระยะไกลอีกต่อไปสำหรับผู้ใช้

สคริปต์จะไปที่นี่:

interface=wlan0
if [[ $# -ge 3 ]]; then interface=$3; fi
thisIP=$(ifconfig | grep $interface -b1 | tail -n1 | egrep -o '[0-9.]{4,}' -m1 | head -n 1)
thisUser=$(whoami)
localFilePath=/tmp/justfortest
destIP=192.168.0.2
destUser=silesia
#dest 
#destFolderOnRemoteMachine=/opt/glassfish/glassfish/
#destFolderOnRemoteMachine=/tmp/

if [[ $# -eq 0 ]]; then 
echo -e "Send file to remote server to locatoin where root permision is needed.\n\tusage: $0 local_filename [username@](ip|host):(remote_folder/|remote_filename) [optionalInterface=wlan0]"
echo -e "Example: \n\ttouch /tmp/justtest &&\n\t $0 /tmp/justtest remoteuser@ssh.superserver.com:/tmp/ "
exit 1
fi

localFilePath=$1

test -e $localFilePath 

destString=$2
usernameAndHost=$(echo $destString | cut -f1 -d':')

if [[ "$usernameAndHost" == *"@"* ]]; then
destUser=$(echo $usernameAndHost | cut -f1 -d'@')
destIP=$(echo $usernameAndHost | cut -f2 -d'@')
else
destIP=$usernameAndHost
destUser=$thisUser
fi

destFolderOnRemoteMachine=$(echo $destString | cut -f2 -d':')

set -e #stop script if there is even single error

echo 'First step: we need to be able to execute scp without any user interaction'
echo 'generating public key on machine, which will receive file'
ssh $destUser@$destIP 'test -e ~/.ssh/id_rsa.pub -a -e ~/.ssh/id_rsa || ssh-keygen -t rsa'
echo 'Done'

echo 'Second step: download public key from remote machine to this machine so this machine allows remote machine (this one receiveing file) to login without asking for password'

key=$(ssh $destUser@$destIP 'cat ~/.ssh/id_rsa.pub')
if ! grep "$key" ~/.ssh/authorized_keys; then
echo $key >> ~/.ssh/authorized_keys
echo 'Added key to authorized hosts'
else
echo "Key already exists in authorized keys"
fi

echo "We will want to execute sudo command remotely, which means turning off asking for password"
echo 'This can be done by this tutorial http://stackoverflow.com/a/10310407/781312'
echo 'This you have to do manually: '
echo -e "execute in new terminal: \n\tssh $destUser:$destIP\nPress enter when ready"
read 
echo 'run there sudo visudo'
read
echo 'change '
echo '    %sudo   ALL=(ALL:ALL) ALL'
echo 'to'
echo '    %sudo   ALL=(ALL:ALL) NOPASSWD: ALL'
echo "After this step you will be done."
read

listOfFiles=$(ssh $destUser@$destIP "sudo ls -a")

if [[ "$listOfFiles" != "" ]]; then 
echo "Sending by executing command, in fact, receiving, file on remote machine"
echo 'Note that this command (due to " instead of '', see man bash | less -p''quotes'') is filled with values from local machine'
echo -e "Executing \n\t""identy=~/.ssh/id_rsa; sudo scp -i \$identy $(whoami)@$thisIP:$(readlink -f $localFilePath) $destFolderOnRemoteMachine"" \non remote machine"
ssh $destUser@$destIP "identy=~/.ssh/id_rsa; sudo scp -i \$identy $(whoami)@$thisIP:$(readlink -f $localFilePath) $destFolderOnRemoteMachine"
ssh $destUser@$destIP "ls ${destFolderOnRemoteMachine%\\\\n}/$(basename $localFilePath)"
if [[ ! "$?" -eq 0 ]]; then echo "errror in validating"; else echo -e "SUCCESS! Successfully sent\n\t$localFilePath \nto \n\t$destString\nFind more at http://arzoxadi.tk"; fi
else
echo "something went wrong with executing sudo on remote host, failure"

fi
ENDOFSCRIPT
) | sudo tee /usr/bin/scpassudo && chmod +x /usr/bin/scpassudo

@Braiam ใช่แน่ใจว่าขอโทษสำหรับการเชื่อมโยงสคริปต์ยาวสวยและนั่นก็คือเหตุผลที่ :)
test30

1

คุณสามารถรวม ssh, sudo และเช่น tar เพื่อถ่ายโอนไฟล์ระหว่างเซิร์ฟเวอร์โดยไม่สามารถเข้าสู่ระบบในฐานะ root และไม่ได้รับอนุญาตให้เข้าถึงไฟล์กับผู้ใช้ของคุณ นี่เป็นเรื่องตลกเล็กน้อยดังนั้นฉันจึงเขียนสคริปต์เพื่อช่วยในเรื่องนี้ คุณสามารถค้นหาสคริปต์ได้ที่นี่: https://github.com/sigmunau/sudoscp

หรือที่นี่:

#! / bin / ทุบตี
ความละเอียด = 0
จาก = $ 1
เพื่อ = $ 2
เปลี่ยน
เปลี่ยน
ไฟล์ = "$ @"
ถ้าทดสอบ -z "$ จาก" -o -z "$ ถึง" -o -z "$ files"
แล้วก็
    echo "การใช้งาน: $ 0 (ไฟล์) *"
    echo "ตัวอย่าง: $ 0 server1 server2 / usr / bin / myapp"
    ทางออก 1
Fi

read -s -p "ป้อนรหัสผ่าน:" sudopassword
echo ""
temp1 = $ (mktemp)
temp2 = $ (mktemp)
(echo "$ sudopassword"; echo "$ sudopassword" | ssh $ จาก sudo -S tar c -P -C / $ files 2> $ temp1) | ssh $ to sudo -S tar x -v -P -C / 2 > $ temp2
sourceres = $ {PIPESTATUS [0]}
ถ้า [$? -ne 0 -o $ sourceres -ne 0]
แล้วก็
    echo "ล้มเหลว!" > & 2
    echo "$ จากผลลัพธ์:"> & 2
    cat $ temp1> & 2
    echo ""> & 2
    echo "$ to output:"> & 2
    cat $ temp2> & 2
    ความละเอียด = 1
Fi

rm $ temp1 $ temp2
ออกจาก $ res

ยินดีต้อนรับสู่ถาม Ubuntu คุณช่วยรวมสคริปต์ไว้ในคำตอบของคุณได้ไหม? ฉันรู้ว่ามันไม่น่าจะเกิดขึ้น แต่ถ้า repo github ถูกลบออกไปหรือ url เปลี่ยนไปคำตอบก็จะเป็นโมฆะ มันจะดีกว่าที่จะรวมสคริปต์โดยตรงและปล่อยให้ repit GitHub เป็นแหล่งที่มา
Michael Lindman

0

ต่อไปนี้เป็นคำตอบของ Willie Wheeler ที่แก้ไขแล้วซึ่งถ่ายโอนไฟล์ผ่าน tar แต่ยังรองรับการส่งผ่านรหัสผ่านไปยัง sudo บนรีโมตโฮสต์

(stty -echo; read passwd; stty echo; echo $passwd; tar -cz foo.*) \
  | ssh remote_host "sudo -S bash -c \"tar -C /var/www/ -xz; echo\""

ความมหัศจรรย์เล็กน้อยที่นี่คือตัวเลือก -S เพื่อ sudo จากหน้า man sudo:

-S, - stdin เขียนพรอมต์ไปที่ข้อผิดพลาดมาตรฐานและอ่านรหัสผ่านจากอินพุตมาตรฐานแทนการใช้อุปกรณ์ปลายทาง รหัสผ่านจะต้องตามด้วยอักขระขึ้นบรรทัดใหม่

ตอนนี้เราต้องการให้ output ของ tar ถูกส่งไปยัง ssh และเปลี่ยนเส้นทาง stdin ของ ssh ไปยัง stdout of tar เอาวิธีใด ๆ ในการส่งรหัสผ่านไปยัง sudo จากเทอร์มินัลเชิงโต้ตอบ (เราสามารถใช้คุณสมบัติ ASKPASS ของ sudo บนรีโมตปลายทาง แต่เป็นอีกเรื่องหนึ่ง) เราสามารถรับรหัสผ่านไปยัง sudo ได้โดยการจับภาพล่วงหน้าและเตรียมไว้ในเอาต์พุต tar โดยดำเนินการเหล่านั้นใน subshell และ piping output ของ subshell เป็น ssh สิ่งนี้ยังมีข้อได้เปรียบเพิ่มเติมคือไม่ทิ้งตัวแปรสภาพแวดล้อมซึ่งมีรหัสผ่านของเราห้อยอยู่ในเชลล์เชิงโต้ตอบของเรา

คุณจะสังเกตเห็นว่าฉันไม่ได้ 'อ่าน' ด้วยตัวเลือก -p เพื่อพิมพ์พรอมต์ เนื่องจากรหัสผ่านจาก sudo นั้นถูกส่งกลับไปยัง stderr ของเชลล์แบบโต้ตอบของเราผ่าน ssh คุณอาจสงสัยว่า "sudo ทำงานอย่างไรเนื่องจากมันทำงานภายใน ssh ทางด้านขวาของ pipe ของเรา" เมื่อเรารันหลายคำสั่งและไพพ์เอาท์พุทของหนึ่งไปยังอีกเชลล์หลัก (เปลือกโต้ตอบในกรณีนี้) ดำเนินการแต่ละคำสั่งในลำดับทันทีหลังจากดำเนินการก่อนหน้านี้ เนื่องจากแต่ละคำสั่งที่อยู่เบื้องหลังไพพ์จะถูกดำเนินการเชลล์พาเรนต์จะแนบ (เปลี่ยนทิศทาง) stdout ของด้านซ้ายมือไปยัง stdin ของด้านขวามือ จากนั้นเอาต์พุตจะกลายเป็นอินพุตเมื่อผ่านกระบวนการ

$ (stty -echo; read passwd; stty echo; echo $passwd; tar -cz foo.*) | ssh 
remote_host "sudo -S bash -c \"tar -C /var/www/ -xz; echo\""
[sudo] password for bruce: 
[1]+  Stopped                 ( stty -echo; read passwd; stty echo; echo 
$passwd; tar -cz foo.* ) | ssh remote_host "sudo -S bash -c \"tar -C 
/var/www/ -xz; echo\""

$ pstree -lap $$
bash,7168
  ├─bash,7969
  ├─pstree,7972 -lap 7168
  └─ssh,7970 remote_host sudo -S bash -c "tar -C /var/www/ -xz; echo"`

เชลล์แบบโต้ตอบของเราคือ PID 7168, subshell ของเราคือ PID 7969 และกระบวนการ ssh ของเราคือ PID 7970

ข้อเสียเปรียบเพียงอย่างเดียวคือการอ่านจะยอมรับอินพุตก่อนที่ sudo จะมีเวลาในการส่งคืนพร้อมท์ ในการเชื่อมต่อที่รวดเร็วและโฮสต์ระยะไกลที่รวดเร็วคุณจะไม่สังเกตเห็นสิ่งนี้ แต่คุณอาจทำอย่างใดอย่างหนึ่งหากช้า ความล่าช้าใด ๆ จะไม่ส่งผลกระทบต่อความสามารถในการเข้าสู่พรอมต์ มันอาจปรากฏขึ้นหลังจากที่คุณเริ่มพิมพ์

หมายเหตุฉันเพิ่งเพิ่มรายการไฟล์โฮสต์สำหรับ "remote_Host" ลงในเครื่องของฉันเพื่อการสาธิต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.