Bash میں !! اور !$ سے پچھلی command دوبارہ چلائیں
!! پچھلی command دہراتا ہے، جبکہ !$ اس کا آخری argument دیتا ہے۔ Bash کی 6 مفید history expansions اور :p سے command چلنے سے پہلے دکھانا سیکھیں۔
Bash history expansion کیا کرتا ہے
Bash history expansion، bash کے command چلانے سے پہلے shell history سے پچھلی command line دوبارہ تیار کرتا ہے۔ !! پچھلی command دوبارہ چلاتا ہے۔ !$ پچھلی command کے آخری argument کو شامل کرتا ہے۔ یہ substitution متنی ہوتی ہے اور سب سے پہلے انجام پاتی ہے، یعنی bash کے line کو words میں تقسیم کرنے سے پہلے۔ اس لیے دوبارہ حاصل ہونے والی چیز بالکل وہی characters ہوتے ہیں جو پہلی بار ٹائپ کیے گئے تھے۔
چھ صورتیں server پر ہونے والے تقریباً تمام کاموں کے لیے کافی ہیں:
!!پچھلی پوری line دوبارہ چلاتا ہے، جبکہsudo !!اسے root کے طور پر دوبارہ چلاتا ہے۔!$پچھلی line کا آخری argument ہے۔!*پچھلی line کے تمام arguments ہیں۔!nhistory entry نمبر n چلاتا ہے، جبکہ!-nموجودہ مقام سے پیچھے کی طرف گنتی کرتا ہے۔!stringایسی تازہ ترین command چلاتا ہے جوstringسے شروع ہوئی ہو۔^old^newپچھلی line دوبارہ چلاتا ہے اور اس میں پہلےoldکوnewسے بدل دیتا ہے۔
ذیل میں موجود تمام commands آپ اپنے server کے interactive prompt پر ٹائپ کریں گے۔ Scripts میں history expansion بند ہوتی ہے، جس کی وضاحت آخری section میں کی گئی ہے۔
ایک طویل path، صرف ایک بار درج کریں
یہ وہ صورت ہے جس میں یہ طریقہ واقعی وقت بچاتا ہے۔ آپ release directory تیار کر رہے ہیں، اور path اتنا طویل ہے کہ اسے دوسری بار درج کرنے سے typo کا امکان بڑھ جاتا ہے۔
sudo mkdir -p /srv/www/app/releases/2026-08-07
sudo chown -R deploy:deploy !$
ls -ld !$
sudo -u deploy nano !$/config.envہر لائن چلانے سے پہلے، bash اس expansion سے بننے والی لائن دکھاتا ہے:
sudo chown -R deploy:deploy /srv/www/app/releases/2026-08-07یہ echo آپ کی جانچ ہے۔ command کے output سے پہلے اسے پڑھیں، کیونکہ یہی واحد موقع ہے جب آپ دیکھ سکتے ہیں کہ bash نے !$ سے کیا مراد لی۔
یہ سلسلہ اس لیے برقرار رہتا ہے کہ bash تاریخ میں آپ کی درج کردہ !$ کے بجائے expanded لائن محفوظ کرتا ہے۔ اس لیے لائن 3 اپنا آخری argument expanded لائن 2 سے لیتی ہے، اور لائن 4 اسے لائن 3 سے لیتی ہے۔ لائن 4 یہ بھی دکھاتی ہے کہ designator کے بعد text آ سکتا ہے: !$/config.env آخر میں /config.env والی path بن جاتا ہے، کیونکہ word designator / پر ختم ہو جاتا ہے۔
اسی session کی ایک اور مثال دیکھیں۔ file میں ترمیم کرنے کے بعد، آپ اس directory کی فہرست دکھانا چاہتے ہیں جس میں وہ file موجود ہے:
ls -l !$:h:h head modifier ہے۔ یہ path سے آخری component ہٹا دیتا ہے، یعنی وہی کام جو dirname کرتا ہے۔ :t صرف آخری component رکھتا ہے، :r extension ہٹا دیتا ہے، اور :e صرف extension رکھتا ہے۔
!! اور sudo !! کے ساتھ پچھلی command دوبارہ چلائیں
آپ sudo بھول جاتے ہیں، اور service manager اس کی نشاندہی کرتا ہے:
systemctl restart nginxFailed to restart nginx.service: Interactive authentication required.sudo !!Bash !! کو پچھلی line کے متن سے replace کرتا ہے، اس لیے shell sudo systemctl restart nginx چلاتی ہے۔
!! عین پچھلی line ہوتی ہے، چاہے وہ line کچھ بھی ہو۔ یہیں عام غلطی ہوتی ہے۔ آپ سمجھتے ہیں کہ ناکام ہونے والی command آخری command تھی، لیکن اس کے بعد آپ نے cd یا history چلایا ہو سکتا ہے، یا ناکام command دو lines پہلے ہو سکتی ہے۔ اس صورت میں sudo !! غلط command کو root privileges کے ساتھ چلا دیتی ہے۔ جب یقین نہ ہو تو پہلے اسے print کریں:
sudo !!:p:p expanded line کو print کرتی ہے اور اسے چلاتی نہیں۔ Printed line آپ کی history میں شامل ہو جاتی ہے، اس لیے اگر وہ درست ہو تو اگلی line میں صرف !! چلانے سے وہ command execute ہو جاتی ہے۔
!$ کے ساتھ آخری argument دوبارہ استعمال کریں
!$ پچھلی سطر کا آخری لفظ ہے۔ آپ زیادہ تر یہی form استعمال کریں گے، کیونکہ آخری لفظ عموماً وہی چیز ہوتا ہے جس پر آپ کام کر رہے ہوتے ہیں: کوئی path یا service name۔
sudo systemctl status nginx
sudo systemctl reload !$یہاں دو باتیں صارفین کو حیران کرتی ہیں۔
اول، !$ آخری word ہوتا ہے، نہ کہ وہ آخری argument جسے آپ ذہن میں رکھے ہوئے تھے۔ اگر پچھلی سطر redirection پر ختم ہوئی ہو تو آخری word، redirect target ہوتا ہے:
sudo nginx -T > /tmp/nginx-dump.conf
less !$یہ مثال درست نتیجہ دیتی ہے۔ لیکن journalctl -u nginx > /tmp/log.txt کے بعد !$، /tmp/log.txt ہوتا ہے، nginx نہیں۔ echoed سطر پڑھیں۔
دوم، یہ expansion متنی ہوتی ہے، اس لیے کوئی variable غیر expanded حالت میں واپس آتا ہے۔ ls $HOME/backups کے بعد !$ آپ کو $HOME/backups کے characters دیتا ہے، جنہیں bash پھر normal parameter کے طور پر دوبارہ expand کرتا ہے۔ اس ترتیب کو یاد رکھیں: history expansion، parameter expansion اور $( ) کے ساتھ command substitution سے پہلے چلتی ہے، اس لیے اسے values نظر نہیں آتیں، صرف text نظر آتا ہے۔
قریب کی forms جاننا مفید ہے۔ !^ پہلا argument ہے، !:2 دوسرا argument ہے، اور !:2-4 ایک range ہے۔ !!:$، !$ لکھنے کا طویل طریقہ ہے۔
اگر آپ اسے نافذ کرنے سے پہلے text دیکھنا چاہتے ہیں تو Alt-. دبائیں، یا Esc اور پھر . دبائیں۔ Readline پچھلی command کا آخری argument براہ راست آپ کے prompt میں داخل کر دیتا ہے، جہاں آپ اس میں ترمیم کر سکتے ہیں۔ اسے دوبارہ دبانے سے اس سے پچھلی command کے آخری argument پر واپس چلے جاتے ہیں۔ جب تک آپ Enter نہ دبائیں، کچھ بھی execute نہیں ہوتا۔
ہر argument کو !* کے ساتھ آگے منتقل کریں۔
!* پچھلی سطر کے پہلے لفظ کے علاوہ ہر لفظ ہے۔
stat /srv/www/app/shared/config.env /srv/www/app/shared/secrets.env
sudo chmod 600 !*فقرہ "پہلے لفظ کے علاوہ" اہم کردار ادا کرتا ہے۔ !* لفظ 0 کو حذف کرتا ہے اور اس کے علاوہ کچھ نہیں حذف کرتا، اس لیے options paths کے ساتھ منتقل ہو جاتے ہیں۔ ls -l file1 file2 کے بعد !*، -l file1 file2 ہے، اس لیے sudo chmod 600 !* ناکام ہوتا ہے، کیونکہ chmod کو -l بطور argument موصول ہوتا ہے۔ الفاظ کو صفر سے شمار کریں اور اس کے بجائے slice لیں: !!:2* سے مراد لفظ 2 سے آخر تک کے تمام الفاظ ہیں۔
یہی مسئلہ sudo کے ساتھ بھی پیش آتا ہے۔ sudo chown deploy:deploy /srv/www/app کے بعد لفظ 0، sudo ہے اور لفظ 1، chown ہے، اس لیے !* اگلی command کو chown deploy:deploy /srv/www/app فراہم کرتا ہے۔ عموماً آپ یہی نہیں چاہتے تھے۔
مقام کے ذریعے کمانڈ منتخب کرنے کے لیے !n اور !-n استعمال کریں
history ہر اندراج کے سامنے نمبر کے ساتھ فہرست دکھاتا ہے۔
history 5 512 sudo nginx -t
513 sudo systemctl reload nginx
514 ss -tulpn
515 sudo tail -f /var/log/nginx/error.log
516 history 5!513 اندراج 513 دوبارہ چلاتا ہے۔ !-2 موجودہ ٹائپ کی جانے والی لائن سے گنتے ہوئے، دو لائن پہلے والا اندراج چلاتا ہے، اس لیے !-1 اور !! کا مطلب ایک ہی ہے۔
استعمال سے فوراً پہلے نمبرز چیک کریں۔ !-2 ہر بار کوئی بھی چیز چلانے پر نئی جگہ کی طرف اشارہ کرتا ہے، بشمول وہ ls جسے آپ نے بغیر سوچے چلایا ہو۔ مطلق نمبرز ایک ہی session کے اندر مستقل رہتے ہیں، لیکن اسی box پر دوسرے session میں یہی نمبرز مختلف ہوتے ہیں۔ اگلے login کے بعد history file دوبارہ پڑھنے پر بھی نمبرز تبدیل ہو جاتے ہیں۔ کل یاد کیا ہوا نمبر آج کسی مختلف کمانڈ کی طرف اشارہ کرتا ہے۔
!string کے سابقے کے ساتھ کمانڈ دوبارہ چلائیں
!string اس تازہ ترین کمانڈ کو چلاتا ہے جو string سے شروع ہوتی ہے۔
!ssیہ اوپر دی گئی فہرست میں سے ss -tulpn کو دوبارہ چلاتا ہے۔ یہ وہ listening socket check ہے جس کی وضاحت Linux server پر کون سے ports کھلے ہیں میں کی گئی ہے۔ !?string? لائن کے آغاز کے بجائے اس میں کہیں بھی match کرتا ہے۔ جب آپ کو argument یاد ہو لیکن کمانڈ کا نام یاد نہ ہو تو یہ مفید ہے۔
سابقہ طویل رکھیں۔ !s، ss، sudo، systemctl یا shutdown سے match کرے گا، جو بھی سب سے حال میں چلی ہو۔ کمانڈ چلنے تک آپ کو معلوم نہیں ہوگا کہ کون سی match ہوئی ہے۔ !string:p match دکھاتا ہے لیکن کمانڈ نہیں چلاتا۔ اگر کوئی match نہ ہو تو bash bash: !ss: event not found دکھاتا ہے اور کچھ نہیں چلاتا۔ یہی محفوظ نتیجہ ہے۔
^old^new کے ذریعے ایک typo درست کریں
sudo systemctl status ngnixUnit ngnix.service could not be found.^ngnix^nginxShell پچھلی لائن کو دوبارہ چلاتی ہے اور پہلی ngnix کو nginx سے تبدیل کرتی ہے۔ صرف پہلی مطابقت رکھنے والی جگہ تبدیل ہوتی ہے۔ ہر مطابقت رکھنے والی جگہ تبدیل کرنے کے لیے طویل صورت !!:gs/ngnix/nginx/ استعمال کریں، جہاں s کا مطلب substitute ہے اور g کا مطلب پوری لائن پر یہ تبدیلی کرنا ہے۔
چلانے سے پہلے expansion کو پرنٹ کریں
دو عادات اس حادثے کو روکتی ہیں جس میں expansion آپ کی نیت کے بغیر کوئی command چلا دیتی ہے۔
پہلی عادت :p ہے، جسے آپ پہلے دیکھ چکے ہیں۔ اسے expansion کے آخر میں شامل کریں تو bash نتیجہ چلانے کے بجائے پرنٹ کرتا ہے: !!:p یا !systemctl:p۔ پرنٹ کی گئی line آپ کی history میں شامل ہو جاتی ہے، اس لیے اس کے بعد !! چلانے سے وہی چیز run ہو جاتی ہے جو آپ نے ابھی پڑھی تھی۔
دوسری عادت زیادہ مضبوط ہے، کیونکہ اس کے لیے آپ کو ہر expansion کے وقت کچھ یاد رکھنے کی ضرورت نہیں ہوتی:
shopt -s histverifyیہ line ~/.bashrc میں شامل کریں۔ histverify set ہونے پر Enter دبانے سے expansion run نہیں ہوتی۔ Bash expanded line کو واپس prompt میں لکھ دیتا ہے تاکہ آپ اسے پڑھ کر edit کر سکیں، اور اسے run کرنے کے لیے دوسری بار Enter دبائیں۔ اس میں ایک اضافی keystroke لگتی ہے اور حادثے کے اس پورے امکان کو ختم کر دیتی ہے۔ اس کے لیے readline درکار ہے، اس لیے یہ صرف interactive prompt پر کام کرتی ہے، کسی اور جگہ نہیں۔
Ctrl-R کے ذریعے بھی کام کیا جا سکتا ہے، اور یہ کبھی کوئی expansion نہیں کرتی۔ Ctrl-R دبائیں اور command کا کچھ حصہ لکھیں۔ Prompt تبدیل ہو کر reverse-i-search prompt بن جاتا ہے اور آپ کے لکھتے ہی تازہ ترین match دکھاتا ہے۔ پرانے matches پر واپس جانے کے لیے دوبارہ Ctrl-R دبائیں۔ Enter دکھائی جانے والی line کو run کرتا ہے۔ Search منسوخ کرنے اور اصل prompt واپس لانے کے لیے Ctrl-G دبائیں۔ Left arrow key search ختم کر دیتی ہے اور matched line کو editing کے لیے prompt میں چھوڑ دیتی ہے۔
جب آپ command کو پہلے دیکھنا چاہتے ہوں تو Ctrl-R استعمال کریں۔ جب command ایک line پہلے والی ہو اور آپ اسے اب بھی screen پر پڑھ سکتے ہوں تو !! اور !$ استعمال کریں۔
echo "done!" میں event not found کیوں آتا ہے
echo "deploy done!"bash: !": event not foundHistory expansion، quoting مکمل ہونے سے پہلے چلتی ہے، اور double quotes، ! character کو محفوظ نہیں کرتیں۔ صرف single quotes اور backslash ایسا کرتے ہیں۔ اس لیے echo 'deploy done!' آپ کی توقع کے مطابق output دیتا ہے۔ Backslash بھی expansion روک دیتا ہے، لیکن double quotes کے اندر bash output میں backslash برقرار رکھتا ہے، اس لیے single quotes صاف اور درست حل ہیں۔
یہ مسئلہ passwords کے ساتھ زیادہ پیش آتا ہے، کیونکہ مضبوط password میں اکثر ! شامل ہوتا ہے۔ mysql -u app -p"S3cret!pass" جیسی command یا تو event-not-found error کے ساتھ fail ہو جاتی ہے، یا اگر history میں کوئی matching entry موجود ہو تو خاموشی سے مختلف string بھیج دیتی ہے۔ Single quotes استعمال کریں، یا اس سے بہتر یہ ہے کہ tool سے prompt دکھانے کو کہیں تاکہ secret command line تک پہنچے ہی نہیں۔ یہ عادت account hygiene کے دیگر اصولوں کا حصہ ہے: نئے VPS پر ابتدائی دس منٹ کے طریقہ کار کے لیے نئے VPS پر ابتدائی دس منٹ دیکھیں، جہاں fresh box پر keys اور passwords سنبھالنے کا طریقہ بیان کیا گیا ہے۔
اگر آپ ! characters سے بھرے ہوئے text block کو paste کرنے والے ہیں تو session کے لیے expansion کو set +H سے بند کریں، اور set -H سے دوبارہ فعال کریں۔
HISTSIZE، HISTFILESIZE اور آپ کی history کہاں محفوظ ہوتی ہے
دو variables ہیں، اور نام ملتے جلتے ہونے کی وجہ سے لوگ انہیں اکثر ایک دوسرے سے خلط ملط کر دیتے ہیں۔
HISTSIZEوہ commands کی تعداد ہے جو چلنے والا shell memory میں رکھتا ہے۔HISTFILESIZEdisk پر موجود file میں محفوظ رکھی جانے والی lines کی تعداد ہے،~/.bash_historyجب تکHISTFILEکچھ اور نہ کہے۔
shell کے exit ہونے پر file لکھی جاتی ہے، اور اسی وقت اسے HISTFILESIZE lines تک محدود کر دیا جاتا ہے۔ Ubuntu کی default ~/.bashrc میں 1000 اور 2000 values مقرر ہوتی ہیں۔ دیکھیں کہ آپ کی configuration میں اصل values کیا ہیں:
grep HIST ~/.bashrc
echo "$HISTSIZE $HISTFILESIZE $HISTFILE"اگر آپ کی !string searches میں وہ commands بار بار نہ ملیں جنہیں آپ جانتے ہیں کہ آپ نے چلایا تھا، تو دونوں values بڑھا دیں۔ 10000 اور 20000 عام values ہیں اور تقریباً کوئی اضافی لاگت نہیں رکھتے، کیونکہ یہ file plain text ہوتی ہے۔ منفی value کا مطلب ہے کہ کوئی حد مقرر نہیں۔
جب آپ ایک ہفتے بعد server پر واپس آتے ہیں تو timestamps مدد دیتے ہیں:
export HISTTIMEFORMAT='%F %T 'اس کے بعد history ہر entry کے شروع میں date اور time دکھاتا ہے، کیونکہ bash file میں ہر command سے پہلے epoch seconds پر مشتمل comment line لکھنا شروع کر دیتا ہے۔
عام شکایت یہ ہے کہ ایک سے زیادہ terminals استعمال کرنے پر history غائب ہو جاتی ہے۔ ہر shell اپنی list memory میں رکھتا ہے اور exit پر اسے file میں لکھتا ہے۔ اس لیے histappend کے بغیر آخری بند ہونے والا shell دوسرے shells کی محفوظ کردہ history کو overwrite کر دیتا ہے۔ دو settings اس مسئلے کو حل کرتی ہیں:
shopt -s histappend
export PROMPT_COMMAND='history -a'histappend shell کو file replace کرنے کے بجائے اپنی list file کے آخر میں شامل کرنے کا حکم دیتا ہے۔ history -a ہر prompt کے بعد نئی lines append کرتا ہے، اس لیے وہ session بھی اپنی commands محفوظ چھوڑ دیتا ہے جسے صاف طور پر close کرنے کے بجائے terminate کر دیا جائے۔ Ubuntu کی default ~/.bashrc میں histappend پہلے ہی مقرر ہوتا ہے۔ جتنی زیادہ machines آپ چلاتے ہیں، یہ اتنا ہی اہم ہو جاتا ہے، کیونکہ history ہر user اور ہر machine کے لیے الگ محفوظ ہوتی ہے۔ اس لیے جب آپ ایک workstation سے کئی servers manage کر رہے ہوں تو مطلوبہ !$ شاید کسی دوسرے host پر موجود ہو۔
اپنی bash history سے secrets کو باہر رکھنا
HISTCONTROL یہ طے کرتا ہے کہ کون سی lines محفوظ کی جائیں گی۔
ignorespaceایسی ہر line کو خارج کرتا ہے جو space سے شروع ہو۔ignoredupsایسی line کو خارج کرتا ہے جو اس سے پچھلی line کے عین مطابق ہو۔ignorebothاوپر دیے گئے دونوں کام کرتا ہے۔erasedupsمحفوظ کی جانے والی line کی تمام پچھلی copies حذف کرتا ہے۔
export HISTCONTROL=ignorebothignorespace فعال ہونے پر، شروع میں دیا گیا ایک space command کو in-memory list سے باہر رکھتا ہے، اس لیے وہ file تک بھی نہیں پہنچتا۔ اس پر انحصار کرنے سے پہلے echo "$HISTCONTROL" سے اس کی value دیکھیں۔ Ubuntu کا default user .bashrc، ignoreboth set کرتا ہے، لیکن root shell یا minimal image میں یہ unset رہ سکتا ہے۔ ایسی صورت میں شروع کا space کوئی اثر نہیں کرتا اور line عام line کی طرح محفوظ ہو جاتی ہے۔
اس تحفظ کی حدود کے بارے میں حقیقت پسند رہیں۔ یہ line ~/.bash_history سے باہر رہتی ہے۔ Process چلنے کے دوران یہ ps output میں پھر بھی دکھائی دیتی ہے، اس لیے system پر موجود کوئی بھی دوسرا user اسے وہاں پڑھ سکتا ہے۔ sudo چلائے گئے command کو system log میں record کرتا ہے۔ History file plain text ہوتی ہے، اس لیے اس کا mode 600 رکھیں، اور یاد رکھیں کہ جو بھی آپ کی home directory پڑھ سکتا ہے وہ آپ کے آخری چند ہزار commands بھی پڑھ سکتا ہے۔
اگر کوئی حساس چیز پہلے ہی list میں موجود ہو تو entry ہٹا کر file دوبارہ لکھیں:
history
history -d 517
history -whistory -d اس entry کو memory سے ہٹاتا ہے، اور history -w موجودہ list کو file پر لکھ دیتا ہے۔ history -c پوری list صاف کرتا ہے۔ HISTIGNORE secrets کے بجائے noise کے لیے متعلقہ setting ہے: HISTIGNORE='ls:pwd:history:clear' ان lines کو list سے باہر رکھتا ہے تاکہ آپ کی searches میں مفید نتائج آئیں۔
شیل اسکرپٹ میں history expansion کچھ نہیں کرتی
History expansion صرف interactive shells میں کام کرتی ہے۔ اسکرپٹ non-interactive shell میں چلتی ہے، جہاں history list فعال نہیں ہوتی اور expansion بند ہوتی ہے، اس لیے !! اور !$ لائن میں عام متن کے طور پر رہتے ہیں۔ اسکرپٹ کے اندر sudo !!، sudo سے لفظی طور پر !! نام کی command چلانے کو کہتا ہے، اور یہ ناکام ہو جاتی ہے۔
آپ جس shell میں موجود ہیں، اس میں یہ command چلا کر جانچ کریں:
echo $-Output موجودہ option flags کا مجموعہ ہوتا ہے، مثلاً himBHs۔ i کا مطلب ہے کہ shell interactive ہے، جبکہ H کا مطلب ہے کہ history expansion فعال ہے۔ یہی لائن کسی اسکرپٹ کے اندر چلائیں تو دونوں حروف موجود نہیں ہوں گے۔
یہی آپ کے shell کے ساتھ کام کرنے کے دو طریقوں کے درمیان بنیادی فرق ہے۔ Prompt پر !$ اور Ctrl-R ان commands پر typing کم کرتے ہیں جو آپ اب بھی دیکھ سکتے ہیں۔ File میں آپ چیزوں کے نام واضح طور پر دیتے ہیں: path کو variable میں رکھیں، یا command substitution کے ذریعے output حاصل کریں۔ اگر کوئی اسکرپٹ آپ کی ذاتی history پر منحصر ہو تو اسے چلانے والے اگلے شخص کے لیے اس کا نتیجہ مختلف ہوگا، جو اسکرپٹ کے مقصد کے بالکل خلاف ہے۔
اسی وجہ سے اس صفحے کی ہر مثال live prompt پر type کرنے کے لیے ہے۔ .sh file میں paste کرنے پر ان میں سے کوئی بھی چیز اسی طرح کام نہیں کرے گی۔
FAQ
bash میں !! کیا کرتا ہے؟
!! پچھلی command line کے مکمل متن میں expand ہوتا ہے، اس لیے sudo !! آپ کی آخری command کو root کے طور پر دوبارہ چلاتا ہے۔ یہ expansion متنی ہوتی ہے اور bash کے line کو parse کرنے سے پہلے مکمل ہو جاتی ہے، جبکہ bash اسے چلانے سے فوراً پہلے مکمل شدہ line دکھاتا ہے۔ اگر آپ کو یقین نہ ہو کہ پچھلی line کیا تھی تو پہلے sudo !!:p ٹائپ کریں۔ :p expansion دکھاتا ہے مگر اسے چلاتا نہیں، اور دکھائی گئی line کو history میں شامل کر دیتا ہے، اس لیے اس کے بعد !! اسے چلاتا ہے۔
پچھلی command کی آخری argument دوبارہ کیسے استعمال کروں؟
!$ استعمال کریں۔ sudo mkdir -p /srv/www/app/releases کے بعد line ls -ld !$، ls -ld /srv/www/app/releases بن جاتی ہے۔ یہ line کا آخری word لیتا ہے، اس لیے آخر میں موجود redirection target کو آخری word شمار کیا جاتا ہے۔ آپ اس کے ساتھ متن بھی جوڑ سکتے ہیں: !$/config.env path میں اضافہ کرتا ہے، کیونکہ word designator / پر رک جاتا ہے۔ interactive متبادل Alt-. ہے، جو وہی متن آپ کے prompt میں داخل کرتا ہے تاکہ Enter دبانے سے پہلے آپ اسے پڑھ سکیں۔
میرے متن میں exclamation mark ہونے پر bash "event not found" کیوں کہتا ہے؟
Double quotes ! کو history expansion سے محفوظ نہیں کرتیں، اس لیے echo "done!" bash کو history event تلاش کرنے پر مجبور کرتا ہے اور bash: !": event not found دکھاتا ہے۔ Single quotes اسے محفوظ کرتی ہیں، اس لیے echo 'done!' لکھیں۔ Backslash بھی expansion روک دیتا ہے، لیکن double quotes کے اندر bash output میں backslash برقرار رکھتا ہے۔ ! پر مشتمل طویل block paste کرنے کے لیے session کے دوران expansion کو set +H سے بند کریں۔
میری shell script میں !! اور !$ کیوں کام نہیں کرتے؟
History expansion صرف interactive shells میں فعال ہوتی ہے۔ Script non-interactively چلتی ہے، اس لیے shell history list نہیں بناتی اور !! line میں plain text کے طور پر رہ جاتا ہے۔ یہ دیکھنے کے لیے echo $- چلائیں کہ آپ کس قسم کی shell میں ہیں: interactive shell میں flags کے اندر i اور H شامل ہوتے ہیں، جبکہ script میں دونوں موجود نہیں ہوتے۔ Scripts میں اس کے بجائے variable یا command substitution استعمال کریں۔
اپنا password bash history میں محفوظ ہونے سے کیسے روکوں؟
~/.bashrc میں HISTCONTROL=ignorespace یا HISTCONTROL=ignoreboth set کریں، پھر command کے آغاز میں ایک single space رکھیں؛ اس طرح وہ کبھی محفوظ نہیں ہوگی۔ پہلے echo "$HISTCONTROL" سے value کی تصدیق کریں، کیونکہ اگر یہ unset ہو تو ابتدائی space کوئی اثر نہیں ڈالتی۔ اس سے صرف line ~/.bash_history سے باہر رہتی ہے۔ Command چلتے وقت ps میں اب بھی نظر آتی ہے، اور sudo اس کے چلائے جانے کا log محفوظ کرتا ہے۔ اگر secret پہلے ہی محفوظ ہو چکا ہے تو اس کا number history سے تلاش کریں، پھر file دوبارہ لکھنے کے لیے history -d <number> کے بعد history -w چلائیں۔