mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-08 03:20:12 +08:00
Feature/multilingual quests (#209)
This commit is contained in:
154 files changed
+2712
-108
No files matched your search
@@ -6,7 +6,7 @@ import { ref, defineProps, onMounted } from 'vue'
|
|||||||
import MarkdownText from './MarkdownText.vue'
|
import MarkdownText from './MarkdownText.vue'
|
||||||
import { trpc } from '../utils/trpc'
|
import { trpc } from '../utils/trpc'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t, locale } = useI18n()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
questTitle: {
|
questTitle: {
|
||||||
@@ -52,8 +52,15 @@ const handleColour = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const quest = await trpc.quests.getQuestDetail.query(questId)
|
try {
|
||||||
questInstruction.value = quest.instruction
|
const quest = await trpc.quests.getQuestDetail.query({
|
||||||
|
questId,
|
||||||
|
locale: locale.value,
|
||||||
|
})
|
||||||
|
questInstruction.value = quest.instruction
|
||||||
|
} catch (error) {
|
||||||
|
toast.error('Failed to load quest detail:', error)
|
||||||
|
}
|
||||||
handleColour()
|
handleColour()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -83,7 +90,7 @@ onMounted(async () => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
@click="handleQuests(questId)"
|
@click="handleQuests(questId)"
|
||||||
:style="{ backgroundColor: questColor, color: questTextColor }"
|
:style="{ backgroundColor: questColor, color: questTextColor }"
|
||||||
class="inline-flex justify-center rounded-lg text-base font-black py-3 mt-5 w-full text-lg"
|
class="inline-flex justify-center rounded-lg text-base font-black py-3 mt-5 w-full"
|
||||||
>
|
>
|
||||||
{{ t('quest.start') }}
|
{{ t('quest.start') }}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { trpc } from '../utils/trpc'
|
|||||||
import useUserProfile from '../store/userProfile'
|
import useUserProfile from '../store/userProfile'
|
||||||
import QuestIntro from './QuestIntro.vue'
|
import QuestIntro from './QuestIntro.vue'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t, locale } = useI18n()
|
||||||
const store = useUserProfile()
|
const store = useUserProfile()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
||||||
@@ -66,7 +66,8 @@ async function computeGraphData() {
|
|||||||
if (!store.progress) return
|
if (!store.progress) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const quests = await trpc.quests.getQuests.query()
|
const quests = await trpc.quests.getQuests.query({ locale: locale.value })
|
||||||
|
|
||||||
const dag = new DAG(quests)
|
const dag = new DAG(quests)
|
||||||
const nodesValues = dag.getNodes()
|
const nodesValues = dag.getNodes()
|
||||||
|
|
||||||
@@ -117,6 +118,10 @@ onMounted(async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
watch(() => store.progress, computeGraphData, { deep: true })
|
watch(() => store.progress, computeGraphData, { deep: true })
|
||||||
|
watch(locale, () => {
|
||||||
|
opened.value = null
|
||||||
|
computeGraphData()
|
||||||
|
})
|
||||||
|
|
||||||
const curvedPath = computed(() => {
|
const curvedPath = computed(() => {
|
||||||
return (source: Node, target: Node) => {
|
return (source: Node, target: Node) => {
|
||||||
|
|||||||
@@ -4,15 +4,44 @@ import { useRouter } from 'vue-router'
|
|||||||
import { useToast } from 'vue-toastification'
|
import { useToast } from 'vue-toastification'
|
||||||
import { useSession } from '../../store/session'
|
import { useSession } from '../../store/session'
|
||||||
import { openBugReport, openQuestSurvey } from '../../utils/formbricks'
|
import { openBugReport, openQuestSurvey } from '../../utils/formbricks'
|
||||||
|
import { trpc } from '../../utils/trpc'
|
||||||
|
import type { QuestLocale } from '../../../../packages/constants'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t, locale } = useI18n()
|
||||||
|
const toast = useToast()
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const sessionStore = useSession()
|
const sessionStore = useSession()
|
||||||
const reset = async () => {
|
const reset = async () => {
|
||||||
console.log('resetting...')
|
console.log('resetting...')
|
||||||
await sessionStore.createSession()
|
const selectedLocale = locale.value as QuestLocale
|
||||||
|
const questId = sessionStore.session?.quest
|
||||||
|
|
||||||
|
if (!questId) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const quests = await trpc.quests.getQuests.query({
|
||||||
|
locale: selectedLocale,
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log({
|
||||||
|
selectedLocale,
|
||||||
|
questId,
|
||||||
|
availableQuestIds: quests.map((quest) => quest.id),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!quests.some((quest) => quest.id === questId)) {
|
||||||
|
toast.warning(t('game.language_unavailable'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await sessionStore.createSession()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to reset quest:', error)
|
||||||
|
toast.error(t('game.reset_failed'))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const continuePlay = async () => {
|
const continuePlay = async () => {
|
||||||
try {
|
try {
|
||||||
router.push({ name: 'map' })
|
router.push({ name: 'map' })
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { setLocale, type SupportedLocale } from '../../i18n'
|
import { setLocale } from '../../i18n'
|
||||||
|
import type { QuestLocale } from '../../../../packages/constants'
|
||||||
|
import {
|
||||||
|
SUPPORTED_LOCALES,
|
||||||
|
LOCALE_NAME_MAP,
|
||||||
|
} from '../../../../packages/constants'
|
||||||
|
|
||||||
const { locale } = useI18n({ useScope: 'global' })
|
const { t, locale } = useI18n({ useScope: 'global' })
|
||||||
|
|
||||||
function changeLanguage(event: Event) {
|
function changeLanguage(event: Event) {
|
||||||
const selectedLocale = (event.target as HTMLSelectElement)
|
const selectedLocale = (event.target as HTMLSelectElement)
|
||||||
.value as SupportedLocale
|
.value as QuestLocale
|
||||||
|
|
||||||
setLocale(selectedLocale)
|
setLocale(selectedLocale)
|
||||||
}
|
}
|
||||||
@@ -15,12 +20,14 @@ function changeLanguage(event: Event) {
|
|||||||
<template>
|
<template>
|
||||||
<select
|
<select
|
||||||
:value="locale"
|
:value="locale"
|
||||||
|
:title="t('language.change')"
|
||||||
class="bg-bg-secondary px-3 py-2 text-sm text-text shadow-md outline-none"
|
class="bg-bg-secondary px-3 py-2 text-sm text-text shadow-md outline-none"
|
||||||
aria-label="Language"
|
aria-label="Language"
|
||||||
@change="changeLanguage"
|
@change="changeLanguage"
|
||||||
style="font-size: 2vh"
|
style="font-size: 2vh"
|
||||||
>
|
>
|
||||||
<option value="en">English</option>
|
<option v-for="locale in SUPPORTED_LOCALES" :key="locale" :value="locale">
|
||||||
<option value="zh-TW">繁體中文</option>
|
{{ LOCALE_NAME_MAP[locale] }}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,16 +1,14 @@
|
|||||||
import { createI18n } from 'vue-i18n'
|
import { createI18n } from 'vue-i18n'
|
||||||
|
import type { QuestLocale } from '../../../packages/constants'
|
||||||
|
import { SUPPORTED_LOCALES } from '../../../packages/constants'
|
||||||
import en from './locales/en.json'
|
import en from './locales/en.json'
|
||||||
import zhTW from './locales/zh-TW.json'
|
import zhTW from './locales/zh-TW.json'
|
||||||
|
|
||||||
export const supportedLocales = ['zh-TW', 'en'] as const
|
function isSupportedLocale(locale: string): locale is QuestLocale {
|
||||||
|
return SUPPORTED_LOCALES.includes(locale as QuestLocale)
|
||||||
export type SupportedLocale = (typeof supportedLocales)[number]
|
|
||||||
|
|
||||||
function isSupportedLocale(locale: string): locale is SupportedLocale {
|
|
||||||
return supportedLocales.includes(locale as SupportedLocale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInitialLocale(): SupportedLocale {
|
function getInitialLocale(): QuestLocale {
|
||||||
const savedLocale = localStorage.getItem('locale')
|
const savedLocale = localStorage.getItem('locale')
|
||||||
|
|
||||||
if (savedLocale && isSupportedLocale(savedLocale)) {
|
if (savedLocale && isSupportedLocale(savedLocale)) {
|
||||||
@@ -34,7 +32,7 @@ export const i18n = createI18n({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export function setLocale(locale: SupportedLocale) {
|
export function setLocale(locale: QuestLocale) {
|
||||||
i18n.global.locale.value = locale
|
i18n.global.locale.value = locale
|
||||||
localStorage.setItem('locale', locale)
|
localStorage.setItem('locale', locale)
|
||||||
document.documentElement.lang = locale
|
document.documentElement.lang = locale
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
{
|
{
|
||||||
"language": {
|
"language": {
|
||||||
"change": "Change language",
|
"change": "Change language"
|
||||||
"traditional_chinese": "繁體中文",
|
|
||||||
"english": "English"
|
|
||||||
},
|
},
|
||||||
"landing_nav": {
|
"landing_nav": {
|
||||||
"intro": "Introduction",
|
"intro": "Introduction",
|
||||||
@@ -102,6 +100,9 @@
|
|||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
"continue": "Continue",
|
"continue": "Continue",
|
||||||
"command_book": "Command Book",
|
"command_book": "Command Book",
|
||||||
"cheatsheets": "Cheat Sheets"
|
"cheatsheets": "Cheat Sheets",
|
||||||
|
"reset_to_apply_language": "Reset quest to apply language changes",
|
||||||
|
"reset_failed": "Reset failed",
|
||||||
|
"language_unavailable": "This quest does not support the selected language, please choose another language"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
{
|
{
|
||||||
"language": {
|
"language": {
|
||||||
"change": "切換語言",
|
"change": "切換語言"
|
||||||
"traditional_chinese": "繁體中文",
|
|
||||||
"english": "English"
|
|
||||||
},
|
},
|
||||||
"landing_nav": {
|
"landing_nav": {
|
||||||
"intro": "前言",
|
"intro": "前言",
|
||||||
@@ -102,6 +100,9 @@
|
|||||||
"reset": "重置",
|
"reset": "重置",
|
||||||
"continue": "繼續",
|
"continue": "繼續",
|
||||||
"command_book": "指令之書",
|
"command_book": "指令之書",
|
||||||
"cheatsheets": "指令列表"
|
"cheatsheets": "指令列表",
|
||||||
|
"reset_to_apply_language": "重置關卡以套用語言變更",
|
||||||
|
"reset_failed": "重置失敗",
|
||||||
|
"language_unavailable": "此關卡不支援所選語言,請選擇其他語言"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
import type { QuestLocale } from '../../../packages/constants'
|
||||||
import {
|
import {
|
||||||
FileGraph,
|
FileGraph,
|
||||||
type FileGraphUpdateEvent,
|
type FileGraphUpdateEvent,
|
||||||
@@ -9,6 +10,7 @@ import Socket from '../utils/socket'
|
|||||||
import SocketTerminal from '../utils/terminal'
|
import SocketTerminal from '../utils/terminal'
|
||||||
import type { Session } from '../types'
|
import type { Session } from '../types'
|
||||||
import { trpc } from '../utils/trpc'
|
import { trpc } from '../utils/trpc'
|
||||||
|
import { i18n } from '../i18n'
|
||||||
|
|
||||||
const socket = new Socket()
|
const socket = new Socket()
|
||||||
const term = new SocketTerminal()
|
const term = new SocketTerminal()
|
||||||
@@ -41,11 +43,16 @@ export const useSession = defineStore('session', {
|
|||||||
quest: null,
|
quest: null,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
async setQuest(questId: string) {
|
async setQuest(questId: string, locale: QuestLocale) {
|
||||||
this.quest = await trpc.quests.getQuestDetail.query(questId)
|
this.quest = await trpc.quests.getQuestDetail.query({
|
||||||
|
questId,
|
||||||
|
locale,
|
||||||
|
})
|
||||||
this.questId = questId
|
this.questId = questId
|
||||||
},
|
},
|
||||||
async setSession(session: SessionDetail) {
|
async setSession(session: SessionDetail) {
|
||||||
|
await this.setQuest(session.quest, session.locale)
|
||||||
|
|
||||||
this.session = {
|
this.session = {
|
||||||
...session,
|
...session,
|
||||||
graph: new FileGraph(session.graph),
|
graph: new FileGraph(session.graph),
|
||||||
@@ -60,18 +67,18 @@ export const useSession = defineStore('session', {
|
|||||||
term.focus()
|
term.focus()
|
||||||
},
|
},
|
||||||
async createSession() {
|
async createSession() {
|
||||||
|
const locale = i18n.global.locale.value
|
||||||
const session = await trpc.session.createSession.mutate({
|
const session = await trpc.session.createSession.mutate({
|
||||||
questId: this.questId,
|
questId: this.questId,
|
||||||
|
locale,
|
||||||
})
|
})
|
||||||
await this.setSession(session)
|
await this.setSession(session)
|
||||||
term.send('echo start\n')
|
term.send('echo start\n')
|
||||||
},
|
},
|
||||||
async getActiveSession() {
|
async getActiveSession(questId: string) {
|
||||||
const session = await trpc.session.getActiveSession.query({
|
const session = await trpc.session.getActiveSession.query({ questId })
|
||||||
questId: this.questId,
|
|
||||||
})
|
|
||||||
if (session) {
|
if (session) {
|
||||||
this.setSession(session)
|
await this.setSession(session)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
newUpdate(update: SessionUpdate) {
|
newUpdate(update: SessionUpdate) {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useToast } from 'vue-toastification'
|
||||||
import { computed, onMounted, watch } from 'vue'
|
import { computed, onMounted, watch } from 'vue'
|
||||||
import { useSession } from '../store/session'
|
import { useSession } from '../store/session'
|
||||||
import useUserProfile from '../store/userProfile'
|
import useUserProfile from '../store/userProfile'
|
||||||
@@ -13,6 +15,8 @@ import CompleteModal from '../components/game/CompleteModal.vue'
|
|||||||
import StartButton from '../components/game/StartButton.vue'
|
import StartButton from '../components/game/StartButton.vue'
|
||||||
import { openQuestSurvey } from '../utils/formbricks'
|
import { openQuestSurvey } from '../utils/formbricks'
|
||||||
|
|
||||||
|
const { t, locale } = useI18n()
|
||||||
|
const toast = useToast()
|
||||||
const sessionStore = useSession()
|
const sessionStore = useSession()
|
||||||
const userStore = useUserProfile()
|
const userStore = useUserProfile()
|
||||||
|
|
||||||
@@ -27,6 +31,13 @@ watch(completed, (newValue, oldValue) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(locale, (newLocale) => {
|
||||||
|
const { session } = sessionStore
|
||||||
|
if (session && newLocale !== session.locale) {
|
||||||
|
toast.info(t('game.reset_to_apply_language'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
questId: {
|
questId: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -37,8 +48,12 @@ const props = defineProps({
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
sessionStore.reset()
|
sessionStore.reset()
|
||||||
sessionStore.setup()
|
sessionStore.setup()
|
||||||
await sessionStore.setQuest(props.questId)
|
|
||||||
await sessionStore.getActiveSession()
|
await sessionStore.getActiveSession(props.questId)
|
||||||
|
|
||||||
|
if (!sessionStore.session) {
|
||||||
|
await sessionStore.setQuest(props.questId, locale.value)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -16,3 +16,10 @@ export const getSessionsRequestSchema = z.object({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export type GetSessionsRequest = z.infer<typeof getSessionsRequestSchema>
|
export type GetSessionsRequest = z.infer<typeof getSessionsRequestSchema>
|
||||||
|
|
||||||
|
export const SUPPORTED_LOCALES = ['zh-TW', 'en'] as const
|
||||||
|
export const LOCALE_NAME_MAP: Record<string, string> = {
|
||||||
|
'zh-TW': '繁體中文',
|
||||||
|
en: 'English',
|
||||||
|
}
|
||||||
|
export type QuestLocale = (typeof SUPPORTED_LOCALES)[number]
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import { model, Schema, Types } from 'mongoose'
|
import { model, Schema, Types } from 'mongoose'
|
||||||
|
import type { QuestLocale } from '../constants'
|
||||||
|
import { SUPPORTED_LOCALES } from '../constants'
|
||||||
|
|
||||||
export interface INode {
|
export interface INode {
|
||||||
path: string
|
path: string
|
||||||
@@ -27,6 +29,7 @@ export interface ISession {
|
|||||||
_id: Types.ObjectId
|
_id: Types.ObjectId
|
||||||
user: Types.ObjectId
|
user: Types.ObjectId
|
||||||
quest: string
|
quest: string
|
||||||
|
locale: QuestLocale
|
||||||
containerId: string | null
|
containerId: string | null
|
||||||
containerName: string | null
|
containerName: string | null
|
||||||
status: 'active' | 'finished' | 'inactive'
|
status: 'active' | 'finished' | 'inactive'
|
||||||
@@ -52,6 +55,11 @@ export const Session = model<ISession>(
|
|||||||
ref: 'Quest',
|
ref: 'Quest',
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
locale: {
|
||||||
|
type: String,
|
||||||
|
enum: SUPPORTED_LOCALES,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
containerId: String,
|
containerId: String,
|
||||||
containerName: String,
|
containerName: String,
|
||||||
status: {
|
status: {
|
||||||
|
|||||||
File renamed without changes.
@@ -0,0 +1,92 @@
|
|||||||
|
id: checkpoint-01
|
||||||
|
title: Checkpoint 1
|
||||||
|
image: base
|
||||||
|
instruction: |
|
||||||
|
This quest tests your understanding of:
|
||||||
|
1. `echo`: print text
|
||||||
|
2. `ls`: list the contents of a folder
|
||||||
|
3. `cd`: move between folders
|
||||||
|
4. `pwd`: show your current path
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- path
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- id: start
|
||||||
|
name: Click `Start` to begin
|
||||||
|
condition:
|
||||||
|
command: echo start
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
This quest checks what you have learned in the previous lessons.
|
||||||
|
You will need to choose the commands yourself.
|
||||||
|
Think about which commands can help you complete each task.
|
||||||
|
|
||||||
|
To continue, make the terminal print `next`.
|
||||||
|
|
||||||
|
- id: next
|
||||||
|
name: Make the terminal print `next`
|
||||||
|
requirements:
|
||||||
|
- start
|
||||||
|
condition:
|
||||||
|
output: next
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Now list the contents of your current folder.
|
||||||
|
|
||||||
|
- id: ls-home
|
||||||
|
name: List the contents of the current folder
|
||||||
|
requirements:
|
||||||
|
- next
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: ls
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Enter the `folder03` folder.
|
||||||
|
|
||||||
|
- id: cd-folder03
|
||||||
|
name: Enter `folder03`
|
||||||
|
requirements:
|
||||||
|
- ls-home
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/folder03
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Show your current path in the terminal.
|
||||||
|
|
||||||
|
- id: pwd-folder03
|
||||||
|
name: Show your current path
|
||||||
|
requirements:
|
||||||
|
- cd-folder03
|
||||||
|
condition:
|
||||||
|
command: pwd
|
||||||
|
output: /home/commander/folder03
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Now enter the `folder02` folder
|
||||||
|
and list its contents.
|
||||||
|
|
||||||
|
- id: ls-folder02
|
||||||
|
name: Enter `folder02` and list its contents
|
||||||
|
requirements:
|
||||||
|
- pwd-folder03
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/folder02
|
||||||
|
command: ls
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Finally, stay in `folder02`
|
||||||
|
and list the contents of `folder01`.
|
||||||
|
|
||||||
|
- id: finish
|
||||||
|
name: Stay in `folder02` and list the contents of `folder01`
|
||||||
|
requirements:
|
||||||
|
- ls-folder02
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/folder02
|
||||||
|
output: file1.txt
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Congratulations! You passed this checkpoint!
|
||||||
|
You are ready to move on to the next lessons.
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,7 @@
|
|||||||
|
echo start
|
||||||
|
echo next
|
||||||
|
ls
|
||||||
|
cd folder03
|
||||||
|
pwd
|
||||||
|
cd ../folder02
|
||||||
|
ls ../folder01
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,97 @@
|
|||||||
|
id: checkpoint-02
|
||||||
|
title: Checkpoint 2
|
||||||
|
image: base
|
||||||
|
instruction: |
|
||||||
|
This quest tests your understanding of:
|
||||||
|
1. `cat`: display the contents of a file
|
||||||
|
2. `touch`: create a file
|
||||||
|
3. `mkdir`: create a folder
|
||||||
|
4. Use the `Tab` key for autocompletion
|
||||||
|
5. Topics covered in the previous checkpoint
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- create
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- id: start
|
||||||
|
name: Click `Start` to begin
|
||||||
|
condition:
|
||||||
|
command: echo start
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
This quest checks what you have learned in the previous lessons.
|
||||||
|
You will need to choose the commands yourself.
|
||||||
|
Think about which commands can help you complete each task.
|
||||||
|
|
||||||
|
To continue, make the terminal print `next`.
|
||||||
|
|
||||||
|
- id: next
|
||||||
|
name: Make the terminal print `next`
|
||||||
|
requirements:
|
||||||
|
- start
|
||||||
|
condition:
|
||||||
|
output: next
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Now list the contents of your current folder.
|
||||||
|
|
||||||
|
- id: ls-home
|
||||||
|
name: List the contents of the current folder
|
||||||
|
requirements:
|
||||||
|
- next
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: ls
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Display the contents of `hello.txt`.
|
||||||
|
|
||||||
|
- id: cat-hello
|
||||||
|
name: Display the contents of `hello.txt`
|
||||||
|
requirements:
|
||||||
|
- ls-home
|
||||||
|
condition:
|
||||||
|
command: cat hello.txt
|
||||||
|
output: This is `hello.txt`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Display the contents of the other file, which has a very long name.
|
||||||
|
|
||||||
|
- id: cat-long-filename
|
||||||
|
name: Display the contents of the other file
|
||||||
|
requirements:
|
||||||
|
- cat-hello
|
||||||
|
condition:
|
||||||
|
command: cat pneumonoultramicroscopicsilicovolcanoconiosis.txt
|
||||||
|
output: A name that has been invented for a lung disease caused by breathing in very small pieces of ash or dust.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Now create a folder named `folder`.
|
||||||
|
|
||||||
|
- id: mkdir-folder
|
||||||
|
name: Create a folder named `folder`
|
||||||
|
requirements:
|
||||||
|
- cat-long-filename
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/folder
|
||||||
|
type: directory
|
||||||
|
exists: true
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Finally, inside the `folder` folder,
|
||||||
|
create a file named `file.txt`.
|
||||||
|
|
||||||
|
- id: finish
|
||||||
|
name: Create `file.txt` inside `folder`
|
||||||
|
requirements:
|
||||||
|
- mkdir-folder
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/folder/file.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Congratulations! You passed this checkpoint!
|
||||||
|
You are ready to move on to the next lessons.
|
||||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,7 @@
|
|||||||
|
echo start
|
||||||
|
echo next
|
||||||
|
ls
|
||||||
|
cat hello.txt
|
||||||
|
cat pneumonoultramicroscopicsilicovolcanoconiosis.txt
|
||||||
|
mkdir folder
|
||||||
|
touch folder/file.txt
|
||||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1 @@
|
|||||||
|
A name that has been invented for a lung disease caused by breathing in very small pieces of ash or dust.
|
||||||
File renamed without changes.
@@ -0,0 +1,140 @@
|
|||||||
|
id: checkpoint-03
|
||||||
|
title: Checkpoint 3
|
||||||
|
image: base
|
||||||
|
instruction: |
|
||||||
|
This quest tests your understanding of:
|
||||||
|
1. `cp`: copy files and folders
|
||||||
|
2. `mv`: move or rename files and folders
|
||||||
|
3. `rm`: delete files and folders
|
||||||
|
4. `rmdir`: delete empty folders
|
||||||
|
5. Use options to change a command's behavior, such as `rm -r`
|
||||||
|
6. Topics covered in the previous checkpoints
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- remove
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- id: start
|
||||||
|
name: Click `Start` to begin
|
||||||
|
condition:
|
||||||
|
command: echo start
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
This quest checks what you have learned in the previous lessons.
|
||||||
|
You will need to choose the commands yourself.
|
||||||
|
Think about which commands can help you complete each task.
|
||||||
|
|
||||||
|
To continue, make the terminal print `next`.
|
||||||
|
|
||||||
|
- id: next
|
||||||
|
name: Make the terminal print `next`
|
||||||
|
requirements:
|
||||||
|
- start
|
||||||
|
condition:
|
||||||
|
output: next
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Now list the contents of your current folder.
|
||||||
|
|
||||||
|
- id: ls-home
|
||||||
|
name: List the contents of the current folder
|
||||||
|
requirements:
|
||||||
|
- next
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: ls
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Copy the file inside `folder` to a new file named `world.txt` in the same folder.
|
||||||
|
|
||||||
|
- id: cp-hello-world
|
||||||
|
name: Copy the file inside `folder` as `world.txt`
|
||||||
|
requirements:
|
||||||
|
- ls-home
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/folder/hello.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
- path: /home/commander/folder/world.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Delete the `hello.txt` file inside `folder`.
|
||||||
|
|
||||||
|
- id: rm-hello
|
||||||
|
name: Delete `hello.txt` inside `folder`
|
||||||
|
requirements:
|
||||||
|
- cp-hello-world
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/folder/hello.txt
|
||||||
|
type: file
|
||||||
|
exists: false
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Now move `world.txt` out of `folder`.
|
||||||
|
(Move it into your home folder, `/home/commander`.)
|
||||||
|
|
||||||
|
- id: mv-world-out
|
||||||
|
name: Move `world.txt` out of `folder`
|
||||||
|
requirements:
|
||||||
|
- rm-hello
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/folder/world.txt
|
||||||
|
type: file
|
||||||
|
exists: false
|
||||||
|
- path: /home/commander/world.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Rename `world.txt` back to `hello.txt`
|
||||||
|
and display its contents.
|
||||||
|
|
||||||
|
- id: cat-hello
|
||||||
|
name: Rename `world.txt` to `hello.txt` and display its contents
|
||||||
|
requirements:
|
||||||
|
- mv-world-out
|
||||||
|
condition:
|
||||||
|
command: cat hello.txt
|
||||||
|
files:
|
||||||
|
- path: /home/commander/world.txt
|
||||||
|
type: file
|
||||||
|
exists: false
|
||||||
|
- path: /home/commander/hello.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
output: This is `hello.txt`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Delete the `folder` folder.
|
||||||
|
|
||||||
|
- id: rmdir-folder
|
||||||
|
name: Delete `folder`
|
||||||
|
requirements:
|
||||||
|
- cat-hello
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/folder
|
||||||
|
type: directory
|
||||||
|
exists: false
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Delete the `trash_can` folder.
|
||||||
|
|
||||||
|
- id: finish
|
||||||
|
name: Delete `trash_can`
|
||||||
|
requirements:
|
||||||
|
- rmdir-folder
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/trash_can
|
||||||
|
type: directory
|
||||||
|
exists: false
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Congratulations! You passed this checkpoint!
|
||||||
|
You are ready to move on to the next lessons.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
This is `hello.txt`.
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,12 @@
|
|||||||
|
echo start
|
||||||
|
echo next
|
||||||
|
ls
|
||||||
|
cd folder
|
||||||
|
cp hello.txt world.txt
|
||||||
|
rm hello.txt
|
||||||
|
mv world.txt ..
|
||||||
|
cd ..
|
||||||
|
mv world.txt hello.txt
|
||||||
|
cat hello.txt
|
||||||
|
rmdir folder
|
||||||
|
rm -r trash_can
|
||||||
File renamed without changes.
@@ -0,0 +1 @@
|
|||||||
|
This is `hello.txt`.
|
||||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1 @@
|
|||||||
|
aHR0cHM6Ly9yZXVybC5jYy9YUjZZMDA=
|
||||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,348 @@
|
|||||||
|
id: copy
|
||||||
|
title: Copying Files
|
||||||
|
image: base
|
||||||
|
instruction: |
|
||||||
|
In this quest, you will learn:
|
||||||
|
1. How to copy files with `cp`
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- create
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- id: start
|
||||||
|
name: Click `Start` to begin
|
||||||
|
condition:
|
||||||
|
command: echo start
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Today we will learn how to copy files.
|
||||||
|
First, use `ls` to see which files are in your current folder.
|
||||||
|
hint: Use `ls` to list the files in your current folder
|
||||||
|
|
||||||
|
- id: ls
|
||||||
|
name: List the files in the current folder
|
||||||
|
requirements:
|
||||||
|
- start
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: ls
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You are outside the `/home/commander` folder.
|
||||||
|
Use `cd /home/commander` to return to `/home/commander`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You can see `hello.txt` and `world.txt` in this folder.
|
||||||
|
Use `cat` to display their contents.
|
||||||
|
When you have finished, enter `echo next` to continue!
|
||||||
|
hint: |
|
||||||
|
Use `cat hello.txt` and `cat world.txt` to display the file contents
|
||||||
|
If a command is keeping the terminal busy, press `Ctrl + C` to cancel it
|
||||||
|
|
||||||
|
- id: cat-hello
|
||||||
|
name: Display the contents of `hello.txt`
|
||||||
|
requirements:
|
||||||
|
- ls
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: cat hello.txt
|
||||||
|
output: Hello
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You are outside the `/home/commander` folder.
|
||||||
|
Use `cd /home/commander` to return to `/home/commander`
|
||||||
|
- id: missing_command
|
||||||
|
condition:
|
||||||
|
command: cat
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
To display this file, add its filename after `cat`.
|
||||||
|
If `cat` is waiting for input, press `Ctrl + C` to cancel it.
|
||||||
|
Enter `cat hello.txt` to display the contents of `hello.txt`
|
||||||
|
- id: missing_extension
|
||||||
|
condition:
|
||||||
|
command: cat hello
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Did you forget the `.txt` extension?
|
||||||
|
Enter `cat hello.txt` to display the contents of `hello.txt`
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have displayed the contents of `hello.txt`!
|
||||||
|
Here is what it contains:
|
||||||
|
```
|
||||||
|
Hello
|
||||||
|
```
|
||||||
|
|
||||||
|
- id: cat-world
|
||||||
|
name: Display the contents of `world.txt`
|
||||||
|
requirements:
|
||||||
|
- ls
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: cat world.txt
|
||||||
|
output: World
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You are outside the `/home/commander` folder.
|
||||||
|
Use `cd /home/commander` to return to `/home/commander`
|
||||||
|
- id: missing_command
|
||||||
|
condition:
|
||||||
|
command: cat
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
To display this file, add its filename after `cat`.
|
||||||
|
If `cat` is waiting for input, press `Ctrl + C` to cancel it.
|
||||||
|
Enter `cat world.txt` to display the contents of `world.txt`
|
||||||
|
- id: missing_extension
|
||||||
|
condition:
|
||||||
|
command: cat world
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Did you forget the `.txt` extension?
|
||||||
|
Enter `cat world.txt` to display the contents of `world.txt`
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have displayed the contents of `world.txt`!
|
||||||
|
Here is what it contains:
|
||||||
|
```
|
||||||
|
World
|
||||||
|
```
|
||||||
|
|
||||||
|
- id: cat-next
|
||||||
|
name: Enter `echo next` to continue
|
||||||
|
requirements:
|
||||||
|
- cat-hello
|
||||||
|
- cat-world
|
||||||
|
condition:
|
||||||
|
command: echo next
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Next, let's learn how to copy files.
|
||||||
|
`cp` is short for copy.
|
||||||
|
To copy a file, use `cp [source file] [destination file]`.
|
||||||
|
Use `cp` to copy `hello.txt` to `hello2.txt`.
|
||||||
|
hint: Use `cp hello.txt hello2.txt` to copy `hello.txt` to `hello2.txt`
|
||||||
|
|
||||||
|
- id: cp-hello
|
||||||
|
name: Copy `hello.txt` to `hello2.txt`
|
||||||
|
requirements:
|
||||||
|
- cat-next
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: cp hello.txt hello2.txt
|
||||||
|
files:
|
||||||
|
- path: /home/commander/hello2.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You are outside the `/home/commander` folder.
|
||||||
|
Use `cd /home/commander` to return to `/home/commander`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have copied `hello.txt` to `hello2.txt`!
|
||||||
|
Let's check the contents of `hello2.txt`.
|
||||||
|
hint: Use `cat hello2.txt` to display the contents of `hello2.txt`
|
||||||
|
|
||||||
|
- id: cat-hello2
|
||||||
|
name: Display the contents of `hello2.txt`
|
||||||
|
requirements:
|
||||||
|
- cp-hello
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: cat hello2.txt
|
||||||
|
output: Hello
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You are outside the `/home/commander` folder.
|
||||||
|
Use `cd /home/commander` to return to `/home/commander`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have displayed the contents of `hello2.txt`!
|
||||||
|
As you can see, `hello2.txt` contains exactly the same text as `hello.txt`.
|
||||||
|
Now try copying `world.txt` to `world2.txt`!
|
||||||
|
hint: Use `cp world.txt world2.txt` to copy `world.txt` to `world2.txt`
|
||||||
|
|
||||||
|
- id: cp-world
|
||||||
|
name: Copy `world.txt` to `world2.txt`
|
||||||
|
requirements:
|
||||||
|
- cat-hello2
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: cp world.txt world2.txt
|
||||||
|
files:
|
||||||
|
- path: /home/commander/world2.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You are outside the `/home/commander` folder.
|
||||||
|
Use `cd /home/commander` to return to `/home/commander`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have copied `world.txt` to `world2.txt`!
|
||||||
|
Let's check the contents of `world2.txt`.
|
||||||
|
hint: Use `cat world2.txt` to display the contents of `world2.txt`
|
||||||
|
|
||||||
|
- id: cat-world2
|
||||||
|
name: Display the contents of `world2.txt`
|
||||||
|
requirements:
|
||||||
|
- cp-world
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: cat world2.txt
|
||||||
|
output: World
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You are outside the `/home/commander` folder.
|
||||||
|
Use `cd /home/commander` to return to `/home/commander`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have displayed the contents of `world2.txt`!
|
||||||
|
`world2.txt` contains exactly the same text as `world.txt`.
|
||||||
|
Next, let's learn how to copy folders.
|
||||||
|
Your current folder contains a `notes` folder with a file named `note.txt` inside.
|
||||||
|
We want to copy the entire folder, including its contents, to `notes2`.
|
||||||
|
To copy a folder, add the `-r` option (recursive). This copies the folder and everything inside it.
|
||||||
|
Options let you change how a command behaves.
|
||||||
|
An option often starts with `-` followed by a letter, such as `-r`.
|
||||||
|
Options usually go after the command name and before the filenames.
|
||||||
|
Use `cp -r notes notes2` to copy `notes` to `notes2`.
|
||||||
|
hint: |
|
||||||
|
Use `cp -r notes notes2` to copy `notes` to `notes2`
|
||||||
|
Remember to include `-r` to copy all the contents
|
||||||
|
|
||||||
|
- id: cp-notes
|
||||||
|
name: Copy the `notes` folder to `notes2`
|
||||||
|
requirements:
|
||||||
|
- cat-world2
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: cp -r notes notes2
|
||||||
|
files:
|
||||||
|
- path: /home/commander/notes2
|
||||||
|
type: directory
|
||||||
|
exists: true
|
||||||
|
- path: /home/commander/notes2/note.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You are outside the `/home/commander` folder.
|
||||||
|
Use `cd /home/commander` to return to `/home/commander`.
|
||||||
|
- id: missing_recursive
|
||||||
|
condition:
|
||||||
|
command: cp notes notes2
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Did you forget the `-r` option?
|
||||||
|
Enter `cp -r notes notes2` to copy `notes` to `notes2`
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have copied the `notes` folder to `notes2`!
|
||||||
|
The entire `notes` folder, including its files, has been copied to `notes2`.
|
||||||
|
`cp -r` copies everything in a folder, including files inside any nested folders.
|
||||||
|
|
||||||
|
Finally, let's see what happens when you copy a file to a destination that already exists.
|
||||||
|
Copy `hello.txt` to `world.txt` and see what happens.
|
||||||
|
hint: Use `cp hello.txt world.txt` to copy `hello.txt` to `world.txt`
|
||||||
|
|
||||||
|
- id: cp-overwrite
|
||||||
|
name: Copy `hello.txt` to `world.txt`
|
||||||
|
requirements:
|
||||||
|
- cp-notes
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: cp hello.txt world.txt
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You are outside the `/home/commander` folder.
|
||||||
|
Use `cd /home/commander` to return to `/home/commander`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have copied `hello.txt` to `world.txt`!
|
||||||
|
Let's check the contents of `world.txt`.
|
||||||
|
hint: Use `cat world.txt`
|
||||||
|
|
||||||
|
- id: check-world
|
||||||
|
name: Check the contents of `world.txt`
|
||||||
|
requirements:
|
||||||
|
- cp-overwrite
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: cat world.txt
|
||||||
|
output: Hello
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You are outside the `/home/commander` folder.
|
||||||
|
Use `cd /home/commander` to return to `/home/commander`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
`world.txt` now contains `Hello`!
|
||||||
|
When the destination file already exists, copying another file to it overwrites its contents.
|
||||||
|
Check whether the destination already exists before copying, so you do not accidentally lose data.
|
||||||
|
That covers the basics of copying files!
|
||||||
|
Enter `echo finish` to complete this quest.
|
||||||
|
|
||||||
|
- id: finish
|
||||||
|
name: Congratulations! All tasks completed!
|
||||||
|
requirements:
|
||||||
|
- check-world
|
||||||
|
condition:
|
||||||
|
command: echo finish
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Congratulations! You have completed all the tasks!
|
||||||
|
You now know how to copy files and folders.
|
||||||
|
In the next quest, you will learn how to move files and folders.
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,13 @@
|
|||||||
|
echo start
|
||||||
|
ls
|
||||||
|
cat hello.txt
|
||||||
|
cat world.txt
|
||||||
|
echo next
|
||||||
|
cp hello.txt hello2.txt
|
||||||
|
cat hello2.txt
|
||||||
|
cp world.txt world2.txt
|
||||||
|
cat world2.txt
|
||||||
|
cp -r notes notes2
|
||||||
|
ls notes2
|
||||||
|
cp hello.txt world.txt
|
||||||
|
cat world.txt
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,165 @@
|
|||||||
|
id: create
|
||||||
|
title: Creating Files and Folders
|
||||||
|
image: base
|
||||||
|
instruction: |
|
||||||
|
In this quest, you will learn:
|
||||||
|
1. How to create files with `touch`
|
||||||
|
2. How to create folders with `mkdir`
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- tab
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- id: start
|
||||||
|
name: Click `Start` to begin
|
||||||
|
condition:
|
||||||
|
command: echo start
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
This time, we will learn about the `touch` command.
|
||||||
|
First, use `ls` to list the files in your current folder.
|
||||||
|
You should find that the folder has no files.
|
||||||
|
hint: Enter `ls` to list the files in your current folder
|
||||||
|
|
||||||
|
- id: ls
|
||||||
|
name: List the files in the folder
|
||||||
|
requirements:
|
||||||
|
- start
|
||||||
|
condition:
|
||||||
|
command: ls
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
The terminal shows no output, which means there are no visible files in this folder.
|
||||||
|
You can create a file with `touch [filename]`.
|
||||||
|
Try creating a file named `hello.txt` in the terminal.
|
||||||
|
hint: Enter `touch hello.txt` to create a file
|
||||||
|
|
||||||
|
- id: touch
|
||||||
|
name: Create a file with `touch`
|
||||||
|
requirements:
|
||||||
|
- ls
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/hello.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
exceptions:
|
||||||
|
- id: missing_extension
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/hello
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
It looks like you forgot the `.txt` extension.
|
||||||
|
Try again and make sure the filename is `hello.txt`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
The terminal should show no output.
|
||||||
|
The file tree on the right now shows the new `hello.txt` file.
|
||||||
|
Let's look inside `hello.txt`!
|
||||||
|
Use the `cat` command you learned earlier to display its contents.
|
||||||
|
hint: Enter `cat hello.txt` to display the contents of `hello.txt`
|
||||||
|
|
||||||
|
- id: cat
|
||||||
|
name: Display the contents of `hello.txt` with `cat`
|
||||||
|
requirements:
|
||||||
|
- touch
|
||||||
|
condition:
|
||||||
|
command: cat hello.txt
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Huh? There is nothing there!
|
||||||
|
That's right. A new file created with `touch` is empty.
|
||||||
|
We will learn how to edit file contents in a future lesson.
|
||||||
|
Let's create another file!
|
||||||
|
Try creating another file named `world.txt` in the terminal.
|
||||||
|
hint: Enter `touch world.txt` to create a file
|
||||||
|
|
||||||
|
- id: touch-2
|
||||||
|
name: Create another file named `world.txt` with `touch`
|
||||||
|
requirements:
|
||||||
|
- cat
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/world.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
exceptions:
|
||||||
|
- id: missing_extension
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/world
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
It looks like you forgot the `.txt` extension.
|
||||||
|
Try again and make sure the filename is `world.txt`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Great! You have created your second file.
|
||||||
|
The file tree now shows both `hello.txt` and `world.txt`.
|
||||||
|
Next, let's create a folder!
|
||||||
|
The `mkdir` command creates an empty folder.
|
||||||
|
Use `mkdir [folder name]`.
|
||||||
|
Try creating a folder named `notes` in the terminal.
|
||||||
|
hint: Enter `mkdir notes` to create a folder
|
||||||
|
|
||||||
|
- id: mkdir
|
||||||
|
name: Create the `notes` folder with `mkdir`
|
||||||
|
requirements:
|
||||||
|
- touch-2
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/notes
|
||||||
|
type: directory
|
||||||
|
exists: true
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Great! You have created the `notes` folder.
|
||||||
|
Next, we will create a file named `note.txt` inside `notes`.
|
||||||
|
First, enter the `notes` folder.
|
||||||
|
Remember the `cd` command? Try using it to enter `notes`.
|
||||||
|
hint: |
|
||||||
|
Enter `cd notes` to enter the `notes` folder
|
||||||
|
After typing `cd n`, press `Tab` to complete the folder name
|
||||||
|
|
||||||
|
- id: cd-notes
|
||||||
|
name: Enter the `notes` folder
|
||||||
|
requirements:
|
||||||
|
- mkdir
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/notes
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have entered the `notes` folder.
|
||||||
|
Now try creating a file named `note.txt` inside `notes`.
|
||||||
|
hint: Enter `touch note.txt` to create a file
|
||||||
|
|
||||||
|
- id: touch-note
|
||||||
|
name: Create `note.txt` inside `notes`
|
||||||
|
requirements:
|
||||||
|
- cd-notes
|
||||||
|
condition:
|
||||||
|
files:
|
||||||
|
- path: /home/commander/notes/note.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Great! You have created `note.txt`.
|
||||||
|
Congratulations! You have completed this quest!
|
||||||
|
In the next quest, you will learn how to copy files and folders.
|
||||||
|
Enter `echo finish` to complete this quest.
|
||||||
|
|
||||||
|
- id: END
|
||||||
|
name: Complete the quest
|
||||||
|
requirements:
|
||||||
|
- touch-note
|
||||||
|
condition:
|
||||||
|
command: echo finish
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Congratulations! You have completed this quest!
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
echo start
|
||||||
|
ls
|
||||||
|
touch hello.txt
|
||||||
|
ls
|
||||||
|
cat hello.txt
|
||||||
|
touch world.txt
|
||||||
|
ls
|
||||||
|
mkdir notes
|
||||||
|
ls
|
||||||
|
cd notes
|
||||||
|
touch note.txt
|
||||||
|
ls
|
||||||
File renamed without changes.
@@ -0,0 +1,79 @@
|
|||||||
|
# Running Executable Files
|
||||||
|
|
||||||
|
## Outline
|
||||||
|
|
||||||
|
1. What an executable file is
|
||||||
|
2. How to find an executable with `which`
|
||||||
|
3. How to run an executable file
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
In earlier lessons, you used commands such as `ls`, `cat`, `cp`, `mv`, and `rm`.
|
||||||
|
These commands are **executable files** that the operating system runs when you enter them.
|
||||||
|
For most commands, you can find the corresponding file in the file system.
|
||||||
|
Use `which` to find the file associated with a command.
|
||||||
|
Enter `which [command name]` to display its path.
|
||||||
|
|
||||||
|
> Use `which ls` to find the path to `ls`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The terminal displays `/usr/bin/ls`, the location of the `ls` executable.
|
||||||
|
`/usr/bin` is a system folder containing many standard programs, including commands such as `cat` and `cp`.
|
||||||
|
|
||||||
|
> Use `which cat` to find the path to `cat`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
To run an executable file, enter its path directly.
|
||||||
|
Let's try running a command using the path to its executable.
|
||||||
|
|
||||||
|
> Enter `/usr/bin/ls` to list the contents of your current folder
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
It lists the files in your folder, just as entering `ls` does. You can compare the results yourself.
|
||||||
|
You can still pass arguments. Let's try this with `cat`.
|
||||||
|
|
||||||
|
> Enter `/usr/bin/cat hello.txt` to display the contents of `hello.txt`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
You can see the contents of `hello.txt`, just as you would with `cat`.
|
||||||
|
This makes sense: `cat` is located at `/usr/bin/cat`, so both commands run the same program.
|
||||||
|
A command like this consists of **an executable** plus **arguments**.
|
||||||
|
You can enter `ls` instead of `/usr/bin/ls` because the `PATH` environment variable tells the terminal which *folders* to search for programs.
|
||||||
|
`PATH` and environment variables are beyond this lesson's scope. We will cover them in a future lesson.
|
||||||
|
|
||||||
|
You can also run custom programs, such as the `dog` file in your current folder.
|
||||||
|
|
||||||
|
> Use `cat dog` to display the contents of `dog`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This is a simple program built from `echo` and `sleep` commands.
|
||||||
|
You do not need to understand every detail yet. It prints a few lines of text, with short pauses between them.
|
||||||
|
|
||||||
|
To run a file, specify its path.
|
||||||
|
Since `dog` is in your home folder, its absolute path is `/home/commander/dog`. You can also use the shorter form `~/dog`.
|
||||||
|
|
||||||
|
> Enter `~/dog` to run the `dog` file
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The terminal displays a few words from this dog with an attitude.
|
||||||
|
When you are in the same folder as a program, a relative path is often more convenient than an absolute path.
|
||||||
|
To run a program in your current folder, put `./` before its filename instead of entering just its name.
|
||||||
|
In a path, `.` means the current folder.
|
||||||
|
Now try running `dog` using a relative path.
|
||||||
|
|
||||||
|
> Enter `./dog` to run the `dog` file
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The dog produces the same output as before.
|
||||||
|
This is an example of a simple custom command.
|
||||||
|
You can put a sequence of commands in a file and run them together to handle complex or repetitive tasks.
|
||||||
|
This technique is also useful when running programs written by other people.
|
||||||
|
|
||||||
|
Here is a final challenge: enter the `commands` folder, then run the `lucky` file inside it using a relative path.
|
||||||
@@ -0,0 +1,236 @@
|
|||||||
|
id: execute
|
||||||
|
title: Running Executable Files
|
||||||
|
image: base
|
||||||
|
instruction: |
|
||||||
|
In this quest, you will learn:
|
||||||
|
1. What an executable file is
|
||||||
|
2. How to find an executable with `which`
|
||||||
|
3. How to run an executable file
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- remove
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- id: start
|
||||||
|
name: Click Start
|
||||||
|
condition:
|
||||||
|
command: echo start
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
In earlier lessons, you used commands such as `ls`, `cat`, `cp`, `mv`, and `rm`.
|
||||||
|
These commands are **executable files** that the operating system runs when you enter them.
|
||||||
|
For most commands, you can find the corresponding file in the file system.
|
||||||
|
Use `which` to find the file associated with a command.
|
||||||
|
Enter `which [command name]` to display its path.
|
||||||
|
hint: Use `which ls` to find the path to `ls`
|
||||||
|
|
||||||
|
- id: which-ls
|
||||||
|
name: Find the path to `ls` with `which`
|
||||||
|
requirements:
|
||||||
|
- start
|
||||||
|
condition:
|
||||||
|
command: which ls
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
The terminal displays `/usr/bin/ls`, the location of the `ls` executable.
|
||||||
|
`/usr/bin` is a system folder containing many standard programs.
|
||||||
|
|
||||||
|
Next, let's find the path to `cat`.
|
||||||
|
hint: Use `which cat` to find the path to `cat`
|
||||||
|
|
||||||
|
- id: which-cat
|
||||||
|
name: Find the path to `cat` with `which`
|
||||||
|
requirements:
|
||||||
|
- which-ls
|
||||||
|
condition:
|
||||||
|
command: which cat
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You can see `/usr/bin/cat`, which is also in the `/usr/bin` folder.
|
||||||
|
To run an executable file, **enter its path directly**.
|
||||||
|
Let's try running a command using the path to its executable.
|
||||||
|
|
||||||
|
First, let's see what happens when you run `ls` normally.
|
||||||
|
hint: Enter `ls` to list the contents of your current folder
|
||||||
|
|
||||||
|
- id: ls
|
||||||
|
name: List the current folder with `ls`
|
||||||
|
requirements:
|
||||||
|
- which-cat
|
||||||
|
condition:
|
||||||
|
command: ls
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Your current folder contains the `commands` folder and two files, `dog` and `hello.txt`.
|
||||||
|
Now try running `ls` using its absolute path, `/usr/bin/ls`.
|
||||||
|
hint: Enter `/usr/bin/ls` to list the contents of your current folder
|
||||||
|
|
||||||
|
- id: bin-ls
|
||||||
|
name: Run `ls` using its absolute path
|
||||||
|
requirements:
|
||||||
|
- ls
|
||||||
|
condition:
|
||||||
|
command: /usr/bin/ls
|
||||||
|
exceptions:
|
||||||
|
- id: exception-ls
|
||||||
|
condition:
|
||||||
|
command: ls
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Here, we are practicing running `ls` using its absolute path.
|
||||||
|
Enter `/usr/bin/ls` to list the contents of your current folder.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
It lists the same files as `ls`. Both commands run the program at `/usr/bin/ls`, so the results are the same.
|
||||||
|
|
||||||
|
You can still pass arguments. Try using `/usr/bin/cat` to display the contents of `hello.txt`.
|
||||||
|
hint: Enter `/usr/bin/cat hello.txt`
|
||||||
|
|
||||||
|
- id: bin-cat
|
||||||
|
name: Run `cat` using its absolute path
|
||||||
|
requirements:
|
||||||
|
- bin-ls
|
||||||
|
condition:
|
||||||
|
command: /usr/bin/cat hello.txt
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You can see the contents of `hello.txt`, just as you would with `cat`.
|
||||||
|
Both commands run the program at `/usr/bin/cat`, so the results are the same.
|
||||||
|
|
||||||
|
A command usually has the form `command argument1 argument2 ...`.
|
||||||
|
The `command` is the name or path of the program to run, such as `ls`, `cat`, or `which`.
|
||||||
|
The `arguments` provide information to the program, such as `hello.txt` after `cat`.
|
||||||
|
|
||||||
|
You can enter `ls` instead of `/usr/bin/ls` because an environment variable called `PATH` tells the shell which folders to search for programs.
|
||||||
|
We will learn more about `PATH` in a future lesson.
|
||||||
|
|
||||||
|
Now let's try running a custom command.
|
||||||
|
The file named `dog` in this folder is a custom command provided for this lesson.
|
||||||
|
First, let's see what is written inside it.
|
||||||
|
hint: Use `cat dog` to display the contents of `dog`
|
||||||
|
|
||||||
|
- id: cat-dog
|
||||||
|
name: Display the contents of `dog` with `cat`
|
||||||
|
requirements:
|
||||||
|
- bin-cat
|
||||||
|
condition:
|
||||||
|
command: cat dog
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
This is a simple program built from `echo` and `sleep` commands.
|
||||||
|
You do not need to understand every detail yet. It just prints a few lines of text.
|
||||||
|
|
||||||
|
To run a file, specify its path.
|
||||||
|
Here, the first part of the command is the path to `dog`. This example does not use any arguments.
|
||||||
|
Since `dog` is in your home folder, its absolute path is `/home/commander/dog`.
|
||||||
|
Using the format `executable arguments`, the command is:
|
||||||
|
```
|
||||||
|
/home/commander/dog
|
||||||
|
```
|
||||||
|
hint: Enter `/home/commander/dog` to run the `dog` file
|
||||||
|
|
||||||
|
- id: dog-abs
|
||||||
|
name: Run `dog` using an absolute path
|
||||||
|
requirements:
|
||||||
|
- cat-dog
|
||||||
|
condition:
|
||||||
|
or:
|
||||||
|
- command: /home/commander/dog
|
||||||
|
- command: ~/dog
|
||||||
|
exceptions:
|
||||||
|
- id: exception-dog
|
||||||
|
condition:
|
||||||
|
command: dog
|
||||||
|
error: 'command not found: dog'
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
`dog` cannot be run by name here because it is not in the command search path. Specify the path to its executable file.
|
||||||
|
Here, we are practicing running `dog` using an absolute path.
|
||||||
|
Enter `/home/commander/dog` to run the `dog` file.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
The terminal displays a few words from this dog with an attitude.
|
||||||
|
When you are in the same folder as a program, a relative path is often more convenient than an absolute path.
|
||||||
|
To run a program in your current folder, put `./` before its filename instead of entering just its name.
|
||||||
|
In a path, `.` means the current folder.
|
||||||
|
Now try running `dog` using a relative path.
|
||||||
|
hint: Enter `./dog` to run the `dog` file
|
||||||
|
|
||||||
|
- id: dog-rel
|
||||||
|
name: Run `dog` using a relative path
|
||||||
|
requirements:
|
||||||
|
- dog-abs
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: ./dog
|
||||||
|
exceptions:
|
||||||
|
- id: exception-dog-2
|
||||||
|
condition:
|
||||||
|
command: dog
|
||||||
|
error: 'command not found: dog'
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
`dog` cannot be run by name here because it is not in the command search path. Specify the path to its executable file.
|
||||||
|
Here, we are practicing running `dog` using a relative path.
|
||||||
|
Enter `./dog` to run the `dog` file.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
The dog produces the same output as before.
|
||||||
|
This is an example of a simple custom command.
|
||||||
|
You can put a sequence of commands in a file and run them together to handle complex or repetitive tasks.
|
||||||
|
This technique is also useful when running programs written by other people.
|
||||||
|
|
||||||
|
Here is a final challenge: enter the `commands` folder, then run the `lucky` file inside it using a relative path.
|
||||||
|
hint: |
|
||||||
|
Use `cd` to enter a folder
|
||||||
|
Use `ls` to list the files
|
||||||
|
Enter `./filename` to run a file
|
||||||
|
|
||||||
|
- id: execute-lucky
|
||||||
|
name: Run `lucky` using a relative path
|
||||||
|
requirements:
|
||||||
|
- dog-rel
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/commands
|
||||||
|
command: ./lucky
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
The terminal displays `I am SO LUCKY!!!`, the message printed by `lucky`.
|
||||||
|
Congratulations! You have completed this lesson!
|
||||||
|
Enter `echo finish` to complete this quest.
|
||||||
|
exceptions:
|
||||||
|
- id: exception-lucky
|
||||||
|
condition:
|
||||||
|
command: lucky
|
||||||
|
error: 'command not found: lucky'
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
`lucky` cannot be run by name here because it is not in the command search path. Specify the path to its executable file.
|
||||||
|
|
||||||
|
- id: exception-lucky-2
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: ./lucky
|
||||||
|
error: 'no such file or directory'
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You are outside the `commands` folder, so `./lucky` does not point to the file yet.
|
||||||
|
First, enter `cd commands` to move into `commands`. Then enter `./lucky` to run `lucky` using a relative path.
|
||||||
|
- id: help
|
||||||
|
condition:
|
||||||
|
command: echo help
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Enter the `commands` folder before running `lucky` using a relative path.
|
||||||
|
First, enter `cd commands` to move into `commands`. Then enter `./lucky` to run `lucky` using a relative path.
|
||||||
|
|
||||||
|
- id: END
|
||||||
|
name: Congratulations! All tasks completed!
|
||||||
|
requirements:
|
||||||
|
- execute-lucky
|
||||||
|
condition:
|
||||||
|
command: echo finish
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Congratulations! You have completed this lesson!
|
||||||
|
You now know how to run executable files.
|
||||||
Executable → Regular
File renamed without changes.
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "You ran the dog file"
|
||||||
|
echo "Woof woof woof"
|
||||||
|
sleep 1
|
||||||
|
echo "You know what?"
|
||||||
|
sleep 1
|
||||||
|
echo "I am better than a cat"
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "I am SO LUCKY!!!"
|
||||||
File renamed without changes.
@@ -0,0 +1 @@
|
|||||||
|
Hello! This is a file hello.txt
|
||||||
File renamed without changes.
@@ -0,0 +1,161 @@
|
|||||||
|
id: explore
|
||||||
|
image: base
|
||||||
|
title: Exploring Files
|
||||||
|
instruction: |
|
||||||
|
In this quest, you will learn:
|
||||||
|
1. How to list folder contents with `ls`
|
||||||
|
2. How to move between folders with `cd`
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- get-started
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- id: start
|
||||||
|
name: Click `Start` to begin the lesson
|
||||||
|
condition:
|
||||||
|
command: ^echo start$
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
The terminal has no graphical interface for browsing folder contents.
|
||||||
|
Instead, you can use `ls` to list what is inside a folder.
|
||||||
|
`ls` is short for list. Its first character is a lowercase L.
|
||||||
|
When you enter `ls`, the terminal lists the files and folders in your current folder.
|
||||||
|
Now enter `ls` to see what is in this folder.
|
||||||
|
hint: Enter `ls` to list the contents of the folder
|
||||||
|
|
||||||
|
- id: ls
|
||||||
|
name: List the files in the folder
|
||||||
|
requirements:
|
||||||
|
- start
|
||||||
|
condition:
|
||||||
|
command: ^ls$
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
type: narrative
|
||||||
|
content: |
|
||||||
|
First, return to `/home/commander/`
|
||||||
|
Enter `cd ~` to return to `/home/commander/`
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You should now see the contents of the folder.
|
||||||
|
The file tree on the right has changed too.
|
||||||
|
This folder contains two folders named `folder1` and `folder2`.
|
||||||
|
|
||||||
|
Next, let's learn how to enter a folder.
|
||||||
|
`cd` is short for change directory, which means changing your current folder.
|
||||||
|
Enter `cd [folder name]` to move into a folder.
|
||||||
|
For example, enter `cd folder1` to move into `folder1`.
|
||||||
|
Now enter the `folder1` folder.
|
||||||
|
hint: Enter `cd folder1` to move into `folder1`
|
||||||
|
|
||||||
|
- id: cd-folder1
|
||||||
|
name: Enter `folder1`
|
||||||
|
requirements:
|
||||||
|
- ls
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/folder1
|
||||||
|
exceptions:
|
||||||
|
- id: wrong_spelling
|
||||||
|
condition:
|
||||||
|
command: ^folderl$
|
||||||
|
response:
|
||||||
|
type: narrative
|
||||||
|
content: |
|
||||||
|
`folder1` ends with the number `1`, not the letter `l`.
|
||||||
|
- id: wrong_directory
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
type: narrative
|
||||||
|
content: Enter `cd folder1` to move into `folder1`
|
||||||
|
- id: not_in_home
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
type: narrative
|
||||||
|
content: |
|
||||||
|
First, return to `/home/commander/`
|
||||||
|
Enter `cd ~` to return to `/home/commander/`
|
||||||
|
Then enter `cd folder1` to move into `folder1`
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have entered the `folder1` folder.
|
||||||
|
Notice that the command prompt has changed from
|
||||||
|
`commander:~ $` to
|
||||||
|
`commander:~/folder1 $`.
|
||||||
|
This tells you that you are now in `folder1`.
|
||||||
|
Now list the contents of `folder1`.
|
||||||
|
hint: Enter `ls` to list the contents of the folder
|
||||||
|
|
||||||
|
- id: ls-folder1
|
||||||
|
name: List the contents of `folder1`
|
||||||
|
requirements:
|
||||||
|
- cd-folder1
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/folder1
|
||||||
|
command: ^ls$
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You can see two files in `folder1`, named `file1.txt` and `file2.txt`.
|
||||||
|
Now let's leave `folder1` and return to the original folder.
|
||||||
|
Use `cd ..` to move up to the parent folder.
|
||||||
|
Here, `..` means the parent folder.
|
||||||
|
hint: Enter `cd ..` to move up to the parent folder
|
||||||
|
|
||||||
|
- id: cd_up
|
||||||
|
name: Return to the parent folder
|
||||||
|
requirements:
|
||||||
|
- ls-folder1
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have returned to the parent folder.
|
||||||
|
Use the commands you just learned to enter `folder2`, list its contents, and return to this folder.
|
||||||
|
hint: |
|
||||||
|
Use `cd` to move between folders
|
||||||
|
Use `ls` to list the contents of a folder
|
||||||
|
|
||||||
|
- id: cd-folder2
|
||||||
|
name: Enter `folder2`
|
||||||
|
requirements:
|
||||||
|
- cd_up
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/folder2
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have entered the `folder2` folder.
|
||||||
|
Now list the contents of `folder2`.
|
||||||
|
hint: Use `ls` to list the contents of the folder
|
||||||
|
|
||||||
|
- id: ls-folder2
|
||||||
|
name: List the contents of `folder2`
|
||||||
|
requirements:
|
||||||
|
- cd-folder2
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/folder2
|
||||||
|
command: ^ls$
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You can see two files in `folder2`, named `file3.txt` and `file4.txt`.
|
||||||
|
Now leave `folder2` and return to the original folder.
|
||||||
|
hint: Use `cd ..` to move up to the parent folder
|
||||||
|
|
||||||
|
- id: END
|
||||||
|
name: Return to the original folder
|
||||||
|
requirements:
|
||||||
|
- ls-folder2
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have returned to the original folder.
|
||||||
|
Congratulations! You now know how to use `ls` and `cd`.
|
||||||
|
hint: |
|
||||||
|
Use `cd` to move between folders
|
||||||
|
Use `ls` to list the contents of a folder
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,8 @@
|
|||||||
|
echo start
|
||||||
|
ls
|
||||||
|
cd folder1
|
||||||
|
ls
|
||||||
|
cd ..
|
||||||
|
cd folder2
|
||||||
|
ls
|
||||||
|
cd ..
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
Whitespace-only changes.
Whitespace-only changes.
File renamed without changes.
@@ -0,0 +1,76 @@
|
|||||||
|
id: get-started
|
||||||
|
image: base
|
||||||
|
title: Terminal Basics
|
||||||
|
instruction: |
|
||||||
|
Welcome to Linux Odyssey!
|
||||||
|
This quest introduces the basics of using the terminal.
|
||||||
|
In this quest, you will learn:
|
||||||
|
1. How to use this website
|
||||||
|
2. How to use the terminal
|
||||||
|
3. How to use the `echo` command
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- id: start
|
||||||
|
name: Click `Start` to begin
|
||||||
|
condition:
|
||||||
|
command: ^echo start$
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Hello, brave adventurer!
|
||||||
|
Welcome to Linux Odyssey, an adventure filled with terminal magic!
|
||||||
|
Think of the terminal as your magic wand. You control the computer with **text spells**, a useful skill for any aspiring programmer!
|
||||||
|
The area below is your stage for casting spells: the terminal. Ready to cast your first one?
|
||||||
|
Enter `echo hello` below, then press Enter to see what happens!
|
||||||
|
|
||||||
|
- id: echo-hello
|
||||||
|
name: Enter `echo hello` in the terminal
|
||||||
|
requirements:
|
||||||
|
- start
|
||||||
|
condition:
|
||||||
|
command: ^echo hello$
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Congratulations on running your first command!
|
||||||
|
You should see this in the terminal:
|
||||||
|
```
|
||||||
|
commander:~ $ echo hello
|
||||||
|
hello
|
||||||
|
```
|
||||||
|
The prompt `commander:~ $` means the computer is waiting for a command.
|
||||||
|
After you enter `echo hello`, the computer prints "hello" on the next line.
|
||||||
|
|
||||||
|
A command is like a sentence telling the computer what to do.
|
||||||
|
Take `echo hello`, for example:
|
||||||
|
- `echo` tells the computer to print something
|
||||||
|
- `hello` is the text to print
|
||||||
|
So when you enter `echo hello`, the computer prints "hello".
|
||||||
|
|
||||||
|
Now try making the terminal display the text `next`.
|
||||||
|
If you get stuck, click the `Hint` button for help.
|
||||||
|
hint: |
|
||||||
|
Enter `echo next` to continue to the next step.
|
||||||
|
|
||||||
|
- id: echo-next
|
||||||
|
name: Enter `echo next` in the terminal
|
||||||
|
requirements:
|
||||||
|
- echo-hello
|
||||||
|
condition:
|
||||||
|
command: ^echo next$
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Congratulations! You now know how to use `echo`.
|
||||||
|
You might wonder why we need a command like this.
|
||||||
|
Although `echo` is simple, printing text is a basic building block for many tasks.
|
||||||
|
In this adventure, we will also use `echo` to trigger events.
|
||||||
|
That is all for this quest. Enter `echo finish` to complete it.
|
||||||
|
|
||||||
|
- id: END
|
||||||
|
name: Finish the quest
|
||||||
|
requirements:
|
||||||
|
- echo-next
|
||||||
|
condition:
|
||||||
|
command: ^echo finish$
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Congratulations! You have completed this quest!
|
||||||
|
You have learned how to use `echo` and what it does.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
echo start
|
||||||
|
echo hello
|
||||||
|
echo next
|
||||||
|
echo finish
|
||||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,136 @@
|
|||||||
|
id: move
|
||||||
|
title: Moving Files
|
||||||
|
image: base
|
||||||
|
instruction: |
|
||||||
|
In this quest, you will learn:
|
||||||
|
1. How to move files and folders with `mv`
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- create
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- id: start
|
||||||
|
name: Click `Start` to begin
|
||||||
|
condition:
|
||||||
|
command: echo start
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Today we will learn how to move files and folders.
|
||||||
|
Your current folder contains `hello.txt`, `world.txt`, and a folder named `notes`.
|
||||||
|
First, use `ls` and `cat` to explore their contents.
|
||||||
|
When you have finished, enter `echo next` to continue!
|
||||||
|
hint: |
|
||||||
|
Use `ls` and `ls notes` to list the files in the folders
|
||||||
|
Use `cat hello.txt` and `cat world.txt` to display the file contents
|
||||||
|
When you have finished, enter `echo next` to continue
|
||||||
|
|
||||||
|
- id: next
|
||||||
|
requirements:
|
||||||
|
- start
|
||||||
|
name: Explore the files, then enter `echo next` to continue
|
||||||
|
condition:
|
||||||
|
command: echo next
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Now let's learn how to move files and folders.
|
||||||
|
`mv` is short for move. It moves files and folders.
|
||||||
|
Use `mv [source] [destination]`.
|
||||||
|
Let's start by moving `hello.txt` into the `notes` folder!
|
||||||
|
hint: Use `mv hello.txt notes` to move `hello.txt` into `notes`
|
||||||
|
|
||||||
|
- id: mv-hello
|
||||||
|
requirements:
|
||||||
|
- next
|
||||||
|
name: Move `hello.txt` into `notes`
|
||||||
|
condition:
|
||||||
|
command: mv hello.txt notes
|
||||||
|
files:
|
||||||
|
- path: /home/commander/notes/hello.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
- path: /home/commander/hello.txt
|
||||||
|
type: file
|
||||||
|
exists: false
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Well done!
|
||||||
|
`hello.txt` has been moved into `notes`!
|
||||||
|
|
||||||
|
`mv` can also rename files!
|
||||||
|
Just use the new name as the destination.
|
||||||
|
Now rename `world.txt` to `wow.txt`.
|
||||||
|
hint: Use `mv world.txt wow.txt` to rename `world.txt` to `wow.txt`
|
||||||
|
|
||||||
|
- id: mv-world
|
||||||
|
requirements:
|
||||||
|
- mv-hello
|
||||||
|
name: Rename `world.txt` to `wow.txt`
|
||||||
|
condition:
|
||||||
|
command: mv world.txt wow.txt
|
||||||
|
files:
|
||||||
|
- path: /home/commander/wow.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
- path: /home/commander/world.txt
|
||||||
|
type: file
|
||||||
|
exists: false
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
`world.txt` is now named `wow.txt`.
|
||||||
|
|
||||||
|
Next, let's learn how to move folders!
|
||||||
|
Moving a folder works the same way as moving a file.
|
||||||
|
`mv` automatically moves everything inside the folder too.
|
||||||
|
First, rename the `notes` folder to `docs`!
|
||||||
|
hint: Use `mv notes docs` to rename `notes` to `docs`
|
||||||
|
|
||||||
|
- id: mv-notes
|
||||||
|
requirements:
|
||||||
|
- mv-world
|
||||||
|
name: Rename `notes` to `docs`
|
||||||
|
condition:
|
||||||
|
command: mv notes docs
|
||||||
|
files:
|
||||||
|
- path: /home/commander/docs
|
||||||
|
type: directory
|
||||||
|
exists: true
|
||||||
|
- path: /home/commander/notes
|
||||||
|
type: directory
|
||||||
|
exists: false
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
The `notes` folder is now named `docs`.
|
||||||
|
Here is a final challenge:
|
||||||
|
Move `docs/hello.txt` to your home folder and rename it to `hi.txt`.
|
||||||
|
hint: Use `mv docs/hello.txt hi.txt` to move the file to your home folder as `hi.txt`
|
||||||
|
|
||||||
|
- id: mv-docs-hello
|
||||||
|
requirements:
|
||||||
|
- mv-notes
|
||||||
|
name: Move `docs/hello.txt` to your home folder as `hi.txt`
|
||||||
|
condition:
|
||||||
|
command: mv docs/hello.txt hi.txt
|
||||||
|
files:
|
||||||
|
- path: /home/commander/hi.txt
|
||||||
|
type: file
|
||||||
|
exists: true
|
||||||
|
- path: /home/commander/docs/hello.txt
|
||||||
|
type: file
|
||||||
|
exists: false
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Well done!
|
||||||
|
You now know how to move files and folders!
|
||||||
|
|
||||||
|
Enter `echo finish` to complete this quest.
|
||||||
|
|
||||||
|
- id: END
|
||||||
|
requirements:
|
||||||
|
- mv-docs-hello
|
||||||
|
name: Complete the quest
|
||||||
|
condition:
|
||||||
|
command: echo finish
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You now know how to move files and folders!
|
||||||
|
Congratulations on completing this quest!
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,11 @@
|
|||||||
|
echo start
|
||||||
|
echo next
|
||||||
|
mv hello.txt notes
|
||||||
|
ls
|
||||||
|
ls notes
|
||||||
|
echo next
|
||||||
|
mv world.txt wow.txt
|
||||||
|
ls
|
||||||
|
mv notes docs
|
||||||
|
ls
|
||||||
|
mv docs/hello.txt hi.txt
|
||||||
File renamed without changes.
@@ -0,0 +1 @@
|
|||||||
|
Hello
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Note
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
World
|
||||||
File renamed without changes.
@@ -0,0 +1,146 @@
|
|||||||
|
id: path
|
||||||
|
title: File Paths
|
||||||
|
image: base
|
||||||
|
instruction: |
|
||||||
|
In this quest, you will learn:
|
||||||
|
1. Absolute and relative paths
|
||||||
|
2. How to show your current path with `pwd`
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- explore
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- id: start
|
||||||
|
name: Click `Start` to begin the lesson
|
||||||
|
condition:
|
||||||
|
command: echo start
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
In Linux, a path describes the location of a file or folder.
|
||||||
|
Paths can be relative or absolute.
|
||||||
|
A relative path starts from your current folder. An absolute path starts from the root folder.
|
||||||
|
First, use `ls` to list the files in this folder.
|
||||||
|
|
||||||
|
- id: ls
|
||||||
|
name: List the files in the folder
|
||||||
|
requirements:
|
||||||
|
- start
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
command: ls
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Now use `cd` to enter the `folder1` folder.
|
||||||
|
|
||||||
|
- id: cd-folder1
|
||||||
|
name: Enter `folder1`
|
||||||
|
requirements:
|
||||||
|
- ls
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/folder1
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have entered `folder1`.
|
||||||
|
In `cd folder1`, the `folder1` part is a relative path.
|
||||||
|
Likewise, `..` in `cd ..` is a relative path.
|
||||||
|
A relative path can span more than one level of folders.
|
||||||
|
For example, to enter `folder2` from here, you could use `cd ..` to go up one level, then `cd folder2` to enter it.
|
||||||
|
You can also join `..` and `folder2` with `/` and enter `cd ../folder2` to get there in one command.
|
||||||
|
Try entering `folder2` this way.
|
||||||
|
hint: Enter `cd ../folder2` to move into `folder2`.
|
||||||
|
|
||||||
|
- id: cd-folder2
|
||||||
|
name: Enter `folder2`
|
||||||
|
requirements:
|
||||||
|
- cd-folder1
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/folder2
|
||||||
|
exceptions:
|
||||||
|
- id: not_in_folder2
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: Enter `cd folder2` to move into `folder2`
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have entered `folder2` using a relative path.
|
||||||
|
You can also add a relative path after `ls` to list the contents of another folder.
|
||||||
|
For example, use `ls ../folder1` to see which files are in `folder1`.
|
||||||
|
Try listing the files in `folder1` this way.
|
||||||
|
hint: Enter `ls ../folder1` to list the files in `folder1`.
|
||||||
|
|
||||||
|
- id: ls-folder1
|
||||||
|
name: List the files in `folder1`
|
||||||
|
requirements:
|
||||||
|
- cd-folder2
|
||||||
|
condition:
|
||||||
|
output: file1.txt
|
||||||
|
exceptions:
|
||||||
|
- id: not_in_folder2
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander/folder2
|
||||||
|
response:
|
||||||
|
content: Return to `folder2` with `cd ~/folder2`, then use `ls ../folder1` to list the contents of `folder1` without leaving `folder2`.
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Great! You now know how to use relative paths.
|
||||||
|
Next, let's look at absolute paths.
|
||||||
|
An absolute path starts from the root folder, which is at the top of the file tree.
|
||||||
|
Use `pwd` to display the absolute path to your current folder.
|
||||||
|
`pwd` stands for `print working directory`: it displays the path to the folder you are in.
|
||||||
|
Now use `pwd` to display your current absolute path.
|
||||||
|
hint: Enter `pwd` to display your current absolute path
|
||||||
|
|
||||||
|
- id: pwd
|
||||||
|
name: Display your current absolute path
|
||||||
|
requirements:
|
||||||
|
- ls-folder1
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander/folder2
|
||||||
|
command: pwd
|
||||||
|
exceptions:
|
||||||
|
- id: not_in_folder2
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
pwd: /home/commander/folder2
|
||||||
|
response:
|
||||||
|
content: Return to `folder2`, then use `pwd` to display your current absolute path
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Your current absolute path is `/home/commander/folder2`.
|
||||||
|
The command prompt also shows your current location.
|
||||||
|
In `commander:~/folder2 $`, `~/folder2` is a shortened form of the path to your current folder.
|
||||||
|
`~` stands for `/home/commander`, your home folder. Each game starts here.
|
||||||
|
You can use absolute paths with `ls` and `cd` too.
|
||||||
|
For example, use `ls ~` to list your home folder or `cd ~` to return to it.
|
||||||
|
Now use `ls ~` to list the contents of your home folder.
|
||||||
|
hint: Enter `ls ~` to list the contents of your home folder
|
||||||
|
|
||||||
|
- id: ls_home
|
||||||
|
name: List the contents of your home folder
|
||||||
|
requirements:
|
||||||
|
- pwd
|
||||||
|
condition:
|
||||||
|
command: ls ~
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
Now use `cd ~` to return to your home folder.
|
||||||
|
hint: Enter `cd ~` to return to your home folder
|
||||||
|
|
||||||
|
- id: END
|
||||||
|
name: Return to your home folder
|
||||||
|
requirements:
|
||||||
|
- ls_home
|
||||||
|
condition:
|
||||||
|
command: cd ~
|
||||||
|
exceptions:
|
||||||
|
- id: already_home
|
||||||
|
condition:
|
||||||
|
pwd: /home/commander
|
||||||
|
response:
|
||||||
|
content: Use `cd ~` to return to your home folder
|
||||||
|
response:
|
||||||
|
content: |
|
||||||
|
You have returned to your home folder.
|
||||||
|
Congratulations! You now know how to use absolute and relative paths and display your current absolute path.
|
||||||
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,8 @@
|
|||||||
|
echo start
|
||||||
|
ls
|
||||||
|
cd folder1
|
||||||
|
cd ../folder2
|
||||||
|
ls ../folder1
|
||||||
|
pwd
|
||||||
|
ls ~
|
||||||
|
cd ~
|
||||||
Loaded 100 of 154 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user