From bd97622f647c7a43dc9345bd3f6c11fb2b029250 Mon Sep 17 00:00:00 2001 From: Fatma Degirmenci Date: Tue, 11 Nov 2025 09:55:42 +0000 Subject: [PATCH 01/10] Complete ls exercises --- individual-shell-tools/ls/script-01.sh | 1 + individual-shell-tools/ls/script-02.sh | 1 + individual-shell-tools/ls/script-03.sh | 1 + individual-shell-tools/ls/script-04.sh | 2 ++ 4 files changed, 5 insertions(+) diff --git a/individual-shell-tools/ls/script-01.sh b/individual-shell-tools/ls/script-01.sh index 241b62f5e..044af3619 100755 --- a/individual-shell-tools/ls/script-01.sh +++ b/individual-shell-tools/ls/script-01.sh @@ -12,4 +12,5 @@ if [[ "${script_dir}" != "$(pwd)" ]]; then fi # TODO: Write a command to list the files and folders in this directory. +ls # The output should be a list of names including child-directory, script-01.sh, script-02.sh, and more. diff --git a/individual-shell-tools/ls/script-02.sh b/individual-shell-tools/ls/script-02.sh index d0a5a10f4..33e4b10bc 100755 --- a/individual-shell-tools/ls/script-02.sh +++ b/individual-shell-tools/ls/script-02.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command which lists all of the files in the directory named child-directory. +ls child-directory # The output should be a list of names: helper-1.txt, helper-2.txt, helper-3.txt. diff --git a/individual-shell-tools/ls/script-03.sh b/individual-shell-tools/ls/script-03.sh index 781216d21..0dc1c2f8a 100755 --- a/individual-shell-tools/ls/script-03.sh +++ b/individual-shell-tools/ls/script-03.sh @@ -3,5 +3,6 @@ set -euo pipefail # TODO: Write a command which _recursively_ lists all of the files and folders in this directory _and_ all of the files inside those folders. +ls -R # The output should be a list of names including: child-directory, script-01.sh, helper-1.txt (and more). # The formatting of the output doesn't matter. diff --git a/individual-shell-tools/ls/script-04.sh b/individual-shell-tools/ls/script-04.sh index 72f3817b3..f5849b255 100755 --- a/individual-shell-tools/ls/script-04.sh +++ b/individual-shell-tools/ls/script-04.sh @@ -14,10 +14,12 @@ touch "${script_dir}/child-directory/helper-3.txt" echo "First exercise (sorted newest to oldest):" # TODO: Write a command which lists the files in the child-directory directory, one per line, sorted so that the most recently modified file is first. +ls -1t child-directory # The output should be a list of names in this order, one per line: helper-3.txt, helper-1.txt, helper-2.txt. echo "Second exercise (sorted oldest to newest):" # TODO: Write a command which does the same as above, but sorted in the opposite order (oldest first). +ls -1tr child-directory # The output should be a list of names in this order, one per line: helper-2.txt, helper-1.txt, helper-3.txt. From 864ee181e0cc713a9c6d6c0287ee0cfd30cbafcb Mon Sep 17 00:00:00 2001 From: Fatma Degirmenci Date: Tue, 11 Nov 2025 10:23:58 +0000 Subject: [PATCH 02/10] Complete cat stretch exercise --- individual-shell-tools/cat/script-01.sh | 1 + individual-shell-tools/cat/script-02.sh | 2 ++ individual-shell-tools/cat/script-03.sh | 2 ++ individual-shell-tools/cat/script-04-stretch.sh | 1 + 4 files changed, 6 insertions(+) diff --git a/individual-shell-tools/cat/script-01.sh b/individual-shell-tools/cat/script-01.sh index c85053e0f..682b379b6 100755 --- a/individual-shell-tools/cat/script-01.sh +++ b/individual-shell-tools/cat/script-01.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output the contents of the helper-1.txt file inside the helper-files directory to the terminal. +cat ../helper-files/helper-1.txt # The output of this command should be "Once upon a time...". diff --git a/individual-shell-tools/cat/script-02.sh b/individual-shell-tools/cat/script-02.sh index 01bbd5eab..680722067 100755 --- a/individual-shell-tools/cat/script-02.sh +++ b/individual-shell-tools/cat/script-02.sh @@ -3,6 +3,8 @@ set -euo pipefail # TODO: Write a command to output the contents of all of the files inside the helper-files directory to the terminal. +cat ../helper-files/helper-1.txt ../helper-files/helper-2.txt ../helper-files/helper-3.txt + # Make sure you are only calling `cat` once. # # The output of this command should be: diff --git a/individual-shell-tools/cat/script-03.sh b/individual-shell-tools/cat/script-03.sh index 37573b0c1..22338dbee 100755 --- a/individual-shell-tools/cat/script-03.sh +++ b/individual-shell-tools/cat/script-03.sh @@ -3,6 +3,8 @@ set -euo pipefail # TODO: Write a command to output the contents of the file `helper-3.txt` inside the helper-files directory to the terminal. +cat -n ../helper-files/helper-3.txt + # This time, we also want to see the line numbers in the output. # # The output of this command should be something like: diff --git a/individual-shell-tools/cat/script-04-stretch.sh b/individual-shell-tools/cat/script-04-stretch.sh index 00fe3c48b..8d74f82b6 100755 --- a/individual-shell-tools/cat/script-04-stretch.sh +++ b/individual-shell-tools/cat/script-04-stretch.sh @@ -5,6 +5,7 @@ set -euo pipefail # NOTE: This is a stretch exercise - it is optional. # TODO: Write a command to output the contents of all of the files in the helper-files directory to the terminal. +cat ../helper-files/helper-1.txt ../helper-files/helper-2.txt ../helper-files/helper-3.txt |awk '{print NR,$0}' # We also want to see the line numbers in the output, but we want line numbers not to reset at the start of each file. # # The output of this command should be something like: From 19ad9cb474c48f51de7f8c6481323f85272ae0c3 Mon Sep 17 00:00:00 2001 From: Fatma Degirmenci Date: Tue, 11 Nov 2025 10:38:10 +0000 Subject: [PATCH 03/10] Complete wc exercises --- individual-shell-tools/wc/script-01.sh | 1 + individual-shell-tools/wc/script-02.sh | 1 + individual-shell-tools/wc/script-03.sh | 1 + 3 files changed, 3 insertions(+) diff --git a/individual-shell-tools/wc/script-01.sh b/individual-shell-tools/wc/script-01.sh index c9dd6e5df..c56cf389b 100755 --- a/individual-shell-tools/wc/script-01.sh +++ b/individual-shell-tools/wc/script-01.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output the number of words in the file helper-files/helper-3.txt. +wc -w < ../helper-files/helper-3.txt # The output should include the number 19. The output should not include the number 92. diff --git a/individual-shell-tools/wc/script-02.sh b/individual-shell-tools/wc/script-02.sh index 8feeb1a62..75365787c 100755 --- a/individual-shell-tools/wc/script-02.sh +++ b/individual-shell-tools/wc/script-02.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output the number of lines in the file helper-files/helper-3.txt. +wc -l < ../helper-files/helper-3.txt # The output should include the number 3. The output should not include the number 19. diff --git a/individual-shell-tools/wc/script-03.sh b/individual-shell-tools/wc/script-03.sh index 6b2e9d3d1..a7cd9b352 100755 --- a/individual-shell-tools/wc/script-03.sh +++ b/individual-shell-tools/wc/script-03.sh @@ -3,6 +3,7 @@ set -euo pipefail # TODO: Write a command to output the number of lines, words, and characters in all of the files inside the helper-files directory. +wc -lwc ../helper-files/helper-1.txt ../helper-files/helper-2.txt ../helper-files/helper-3.txt # The output should be something like: # 1 4 20 ../helper-files/helper-1.txt # 1 7 39 ../helper-files/helper-2.txt From 24b7fc01c88e20d4d084f8450e7ad5ed2936abda Mon Sep 17 00:00:00 2001 From: Fatma Degirmenci Date: Tue, 11 Nov 2025 11:00:35 +0000 Subject: [PATCH 04/10] Complete grep exercises --- individual-shell-tools/grep/script-01.sh | 1 + individual-shell-tools/grep/script-02.sh | 1 + individual-shell-tools/grep/script-03.sh | 1 + individual-shell-tools/grep/script-04.sh | 1 + individual-shell-tools/grep/script-05.sh | 1 + individual-shell-tools/grep/script-06.sh | 1 + individual-shell-tools/grep/script-07.sh | 1 + 7 files changed, 7 insertions(+) diff --git a/individual-shell-tools/grep/script-01.sh b/individual-shell-tools/grep/script-01.sh index fb05f42f2..c4f3a4d4b 100755 --- a/individual-shell-tools/grep/script-01.sh +++ b/individual-shell-tools/grep/script-01.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output every line in dialogue.txt said by the Doctor. +grep "^Doctor" dialogue.txt # The output should contain 6 lines. diff --git a/individual-shell-tools/grep/script-02.sh b/individual-shell-tools/grep/script-02.sh index df6f85640..505da8ec6 100755 --- a/individual-shell-tools/grep/script-02.sh +++ b/individual-shell-tools/grep/script-02.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output every line in dialogue.txt that contains the word Doctor (regardless of case). +grep -i "Doctor" dialogue.txt # The output should contain 9 lines. diff --git a/individual-shell-tools/grep/script-03.sh b/individual-shell-tools/grep/script-03.sh index 5383fe578..82e5f8a60 100755 --- a/individual-shell-tools/grep/script-03.sh +++ b/individual-shell-tools/grep/script-03.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output the number of lines in dialogue.txt that contain the word Doctor (regardless of case). +grep -ic "Doctor" dialogue.txt # The output should be exactly the number 9. diff --git a/individual-shell-tools/grep/script-04.sh b/individual-shell-tools/grep/script-04.sh index 80ee04776..01076d38e 100755 --- a/individual-shell-tools/grep/script-04.sh +++ b/individual-shell-tools/grep/script-04.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output every line in dialogue.txt that does not contain the word "Hello" (regardless of case). +grep -vi "Hello" dialogue.txt # The output should contain 10 lines. diff --git a/individual-shell-tools/grep/script-05.sh b/individual-shell-tools/grep/script-05.sh index 1eb538185..c205ba902 100755 --- a/individual-shell-tools/grep/script-05.sh +++ b/individual-shell-tools/grep/script-05.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output every line in dialogue.txt that contains the string "cure", as well as the line before that line. +grep -i -B 1 "cure" dialogue.txt # The output should contain two pairs of two lines of text (with a separator between them). diff --git a/individual-shell-tools/grep/script-06.sh b/individual-shell-tools/grep/script-06.sh index 5670e3b6c..25d1d56be 100755 --- a/individual-shell-tools/grep/script-06.sh +++ b/individual-shell-tools/grep/script-06.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output the name of every `.txt` file in this directory which contains a line of dialogue said by the Doctor. +grep -l "Doctor" *.txt # The output should contain two filenames. diff --git a/individual-shell-tools/grep/script-07.sh b/individual-shell-tools/grep/script-07.sh index 9670ebad9..f187b3c04 100755 --- a/individual-shell-tools/grep/script-07.sh +++ b/individual-shell-tools/grep/script-07.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output, for each `.txt` file in this directory, how many lines of dialogue the Doctor has. +grep -c "^Doctor" *.txt # The output should show that dialogue.txt contains 6 lines, dialogue-2.txt contains 2, and dialogue-3.txt contains 0. From 4725e687cfaf673b206a48dd71cfccb14b12db4c Mon Sep 17 00:00:00 2001 From: Fatma Degirmenci Date: Tue, 11 Nov 2025 12:51:12 +0000 Subject: [PATCH 05/10] Complete sed exercises --- individual-shell-tools/sed/script-01.sh | 1 + individual-shell-tools/sed/script-02.sh | 1 + individual-shell-tools/sed/script-03.sh | 1 + individual-shell-tools/sed/script-04.sh | 1 + individual-shell-tools/sed/script-05.sh | 1 + individual-shell-tools/sed/script-06.sh | 1 + 6 files changed, 6 insertions(+) diff --git a/individual-shell-tools/sed/script-01.sh b/individual-shell-tools/sed/script-01.sh index 3eba6fa4d..9edc8efe3 100755 --- a/individual-shell-tools/sed/script-01.sh +++ b/individual-shell-tools/sed/script-01.sh @@ -3,5 +3,6 @@ set -euo pipefail # TODO: Write a command to output input.txt with all occurrences of the letter `i` replaced with `I`. +sed 's/i/I/g' input.txt # The output should contain 11 lines. # The first line of the output should be: "ThIs Is a sample fIle for experImentIng with sed.". diff --git a/individual-shell-tools/sed/script-02.sh b/individual-shell-tools/sed/script-02.sh index abdd64d06..e7ec3f486 100755 --- a/individual-shell-tools/sed/script-02.sh +++ b/individual-shell-tools/sed/script-02.sh @@ -3,5 +3,6 @@ set -euo pipefail # TODO: Write a command to output input.txt with numbers removed. +sed 's/[0-9]//g' input.txt # The output should contain 11 lines. # Line 6 of the output should be " Alisha". diff --git a/individual-shell-tools/sed/script-03.sh b/individual-shell-tools/sed/script-03.sh index dd284a296..4be42f03b 100755 --- a/individual-shell-tools/sed/script-03.sh +++ b/individual-shell-tools/sed/script-03.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output input.txt removing any line which contains a number. +sed '/[0-9]/d' input.txt # The output should contain 6 lines. diff --git a/individual-shell-tools/sed/script-04.sh b/individual-shell-tools/sed/script-04.sh index 0052ac6c4..fcac5ae0d 100755 --- a/individual-shell-tools/sed/script-04.sh +++ b/individual-shell-tools/sed/script-04.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output input.txt replacing every occurrence of the string "We'll" with "We will". +sed "s/We'll/We will/g" input.txt # The output should contain 11 lines. diff --git a/individual-shell-tools/sed/script-05.sh b/individual-shell-tools/sed/script-05.sh index 2dcc91a0c..7bdf0d5c9 100755 --- a/individual-shell-tools/sed/script-05.sh +++ b/individual-shell-tools/sed/script-05.sh @@ -3,6 +3,7 @@ set -euo pipefail # TODO: Write a command to output input.txt with one change: +sed 's/^\([0-9]\+\) \(.*\)/\2 \1/' input.txt # If a line starts with a number and a space, make the line instead end with a space and the number. # So line 6 which currently reads "37 Alisha" should instead read "Alisha 37". # The output should contain 11 lines. diff --git a/individual-shell-tools/sed/script-06.sh b/individual-shell-tools/sed/script-06.sh index 0b9390170..3f4a6697b 100755 --- a/individual-shell-tools/sed/script-06.sh +++ b/individual-shell-tools/sed/script-06.sh @@ -3,6 +3,7 @@ set -euo pipefail # TODO: Write a command to output input.txt with one fix: +sed 's/,\([^ ]\)/, \1/g' input.txt # If a comma in input.txt is not followed by a space, add a space after. # If there is already a space after a comma, do not add an additional space. # The output should contain 11 lines. From 7e82c288d38e94bcd3bd560b9ae0e6cbbdfad8be Mon Sep 17 00:00:00 2001 From: Fatma Degirmenci Date: Tue, 11 Nov 2025 13:17:37 +0000 Subject: [PATCH 06/10] Complete awk exercises --- individual-shell-tools/awk/script-01.sh | 1 + individual-shell-tools/awk/script-02.sh | 1 + individual-shell-tools/awk/script-03.sh | 1 + individual-shell-tools/awk/script-04.sh | 1 + individual-shell-tools/awk/script-05.sh | 1 + individual-shell-tools/awk/script-06-stretch.sh | 1 + individual-shell-tools/awk/script-07-stretch.sh | 1 + 7 files changed, 7 insertions(+) diff --git a/individual-shell-tools/awk/script-01.sh b/individual-shell-tools/awk/script-01.sh index 8db4390af..e33ee9a5d 100755 --- a/individual-shell-tools/awk/script-01.sh +++ b/individual-shell-tools/awk/script-01.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output just the names of each player in `scores-table.txt`. +awk '{print $1}' scores-table.txt # Your output should contain 6 lines, each with just one word on it. diff --git a/individual-shell-tools/awk/script-02.sh b/individual-shell-tools/awk/script-02.sh index 5956be9bd..a71a90314 100755 --- a/individual-shell-tools/awk/script-02.sh +++ b/individual-shell-tools/awk/script-02.sh @@ -3,4 +3,5 @@ set -euo pipefail # TODO: Write a command to output the names of each player, as well as their city. +awk '{print $1, $2}' scores-table.txt # Your output should contain 6 lines, each with two words on it, separated by a space. diff --git a/individual-shell-tools/awk/script-03.sh b/individual-shell-tools/awk/script-03.sh index af7c6e8b9..c249fea2d 100755 --- a/individual-shell-tools/awk/script-03.sh +++ b/individual-shell-tools/awk/script-03.sh @@ -3,5 +3,6 @@ set -euo pipefail # TODO: Write a command to output just the names of each player along with the score from their first attempt. +awk '{print $1,$3}' scores-table.txt # Your output should contain 6 lines, each with one word and one number on it. # The first line should be "Ahmed 1". diff --git a/individual-shell-tools/awk/script-04.sh b/individual-shell-tools/awk/script-04.sh index bf15703c7..abcfa4593 100755 --- a/individual-shell-tools/awk/script-04.sh +++ b/individual-shell-tools/awk/script-04.sh @@ -3,5 +3,6 @@ set -euo pipefail # TODO: Write a command to output just the names of each player in London along with the score from their last attempt. +awk '$2== "London" {print $1,$(NF) }' scores-table.txt # Your output should contain 3 lines, each with one word and one number on it. # The first line should be "Ahmed 4". diff --git a/individual-shell-tools/awk/script-05.sh b/individual-shell-tools/awk/script-05.sh index d1680cb02..f84b16b3f 100755 --- a/individual-shell-tools/awk/script-05.sh +++ b/individual-shell-tools/awk/script-05.sh @@ -3,5 +3,6 @@ set -euo pipefail # TODO: Write a command to output just the names of each player along with the number of times they've played the game. +awk '{print $1,NF-2}' scores-table.txt # Your output should contain 6 lines, each with one word and one number on it. # The first line should be "Ahmed 3". diff --git a/individual-shell-tools/awk/script-06-stretch.sh b/individual-shell-tools/awk/script-06-stretch.sh index 0201e6378..89fa135b3 100755 --- a/individual-shell-tools/awk/script-06-stretch.sh +++ b/individual-shell-tools/awk/script-06-stretch.sh @@ -5,4 +5,5 @@ set -euo pipefail # NOTE: This is a stretch exercise - it is optional. # TODO: Write a command to output the total of adding together all players' first scores. +awk '{sum+= $3} END {print sum}' scores-table.txt # Your output should be exactly the number 54. diff --git a/individual-shell-tools/awk/script-07-stretch.sh b/individual-shell-tools/awk/script-07-stretch.sh index 3f7155880..559817344 100755 --- a/individual-shell-tools/awk/script-07-stretch.sh +++ b/individual-shell-tools/awk/script-07-stretch.sh @@ -5,5 +5,6 @@ set -euo pipefail # NOTE: This is a stretch exercise - it is optional. # TODO: Write a command to output just the names of each player along with the total of adding all of that player's scores. +awk ' {s=0; for(i=3; i<=NF; i++) s+=$i; print $1, s}' scores-table.txt # Your output should contain 6 lines, each with one word and one number on it. # The first line should be "Ahmed 15". The second line should be "Basia 37" From c0979ea4b84eae894cf78a32ac186f753e96a0c0 Mon Sep 17 00:00:00 2001 From: Fatma Degirmenci Date: Wed, 19 Nov 2025 14:13:20 +0000 Subject: [PATCH 07/10] Refactor cat file --- individual-shell-tools/cat/script-02.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/individual-shell-tools/cat/script-02.sh b/individual-shell-tools/cat/script-02.sh index 680722067..8fa1ffefe 100755 --- a/individual-shell-tools/cat/script-02.sh +++ b/individual-shell-tools/cat/script-02.sh @@ -3,7 +3,7 @@ set -euo pipefail # TODO: Write a command to output the contents of all of the files inside the helper-files directory to the terminal. -cat ../helper-files/helper-1.txt ../helper-files/helper-2.txt ../helper-files/helper-3.txt +cat ../helper-files/helper-*.txt # Make sure you are only calling `cat` once. # From 937b03d33b820d7b501aecedafdf7cc6c3e81382 Mon Sep 17 00:00:00 2001 From: Fatma Degirmenci Date: Tue, 25 Nov 2025 18:40:52 +0000 Subject: [PATCH 08/10] cat implementation --- implement-shell-tools/cat/cat.js | 40 +++++++ implement-shell-tools/cat/package-lock.json | 118 ++++++++++++++++++++ implement-shell-tools/cat/package.json | 21 ++++ 3 files changed, 179 insertions(+) create mode 100644 implement-shell-tools/cat/cat.js create mode 100644 implement-shell-tools/cat/package-lock.json create mode 100644 implement-shell-tools/cat/package.json diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js new file mode 100644 index 000000000..75853869c --- /dev/null +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,40 @@ +import { program } from "commander"; +import { promises as fs } from "node:fs"; + +program + .name("cat command") + .description("create cat command") + .option("-n", "Number all lines") + .option("-b", "Number non-empty lines") + .argument("", "File paths"); + +program.parse(); +const paths = program.args; +const number = program.opts().n; +const nonEmptyLine = program.opts().b; + +let lineNumber = 1; + +for (const path of paths) { + try { + const read = await fs.readFile(path, "utf-8"); + const lines = read.split("\n"); + for (let i of lines) { + if (number) { + console.log(`${String(lineNumber).padStart(6, " ")} ${i}`); + lineNumber++; + } else if (nonEmptyLine) { + if (i.trim() !== "") { + console.log(`${String(lineNumber).padStart(6, " ")} ${i}`); + lineNumber++; + } else { + console.log(i); + } + } else { + console.log(i); + } + } + } catch (err) { + console.error(`File could not read: ${path}`); + } +} diff --git a/implement-shell-tools/cat/package-lock.json b/implement-shell-tools/cat/package-lock.json new file mode 100644 index 000000000..6f80a2a70 --- /dev/null +++ b/implement-shell-tools/cat/package-lock.json @@ -0,0 +1,118 @@ +{ + "name": "cat", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cat", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "commander": "^14.0.2", + "glob": "^13.0.0", + "lru-cache": "^11.2.2", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "path-scurry": "^2.0.1" + }, + "devDependencies": {} + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/glob": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", + "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "path-scurry": "^2.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lru-cache": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-scurry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + } + } +} diff --git a/implement-shell-tools/cat/package.json b/implement-shell-tools/cat/package.json new file mode 100644 index 000000000..ba939f50b --- /dev/null +++ b/implement-shell-tools/cat/package.json @@ -0,0 +1,21 @@ +{ + "name": "cat", + "version": "1.0.0", + "description": "You should already be familiar with the `cat` command line tool.", + "main": "cat.js", + "type": "module", + "dependencies": { + "commander": "^14.0.2", + "glob": "^13.0.0", + "lru-cache": "^11.2.2", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "path-scurry": "^2.0.1" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} From a17ed5d8ae529c97bbc2482b05a763f6cc59816e Mon Sep 17 00:00:00 2001 From: Fatma Degirmenci Date: Mon, 1 Dec 2025 22:17:21 +0000 Subject: [PATCH 09/10] implement ls command --- implement-shell-tools/cat/package-lock.json | 118 -------------------- implement-shell-tools/cat/package.json | 21 ---- implement-shell-tools/ls/ls.js | 43 +++++++ implement-shell-tools/package-lock.json | 25 +++++ implement-shell-tools/package.json | 16 +++ 5 files changed, 84 insertions(+), 139 deletions(-) delete mode 100644 implement-shell-tools/cat/package-lock.json delete mode 100644 implement-shell-tools/cat/package.json create mode 100644 implement-shell-tools/ls/ls.js create mode 100644 implement-shell-tools/package-lock.json create mode 100644 implement-shell-tools/package.json diff --git a/implement-shell-tools/cat/package-lock.json b/implement-shell-tools/cat/package-lock.json deleted file mode 100644 index 6f80a2a70..000000000 --- a/implement-shell-tools/cat/package-lock.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "name": "cat", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "cat", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "commander": "^14.0.2", - "glob": "^13.0.0", - "lru-cache": "^11.2.2", - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "path-scurry": "^2.0.1" - }, - "devDependencies": {} - }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/glob": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", - "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "path-scurry": "^2.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/path-scurry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", - "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - } - } -} diff --git a/implement-shell-tools/cat/package.json b/implement-shell-tools/cat/package.json deleted file mode 100644 index ba939f50b..000000000 --- a/implement-shell-tools/cat/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "cat", - "version": "1.0.0", - "description": "You should already be familiar with the `cat` command line tool.", - "main": "cat.js", - "type": "module", - "dependencies": { - "commander": "^14.0.2", - "glob": "^13.0.0", - "lru-cache": "^11.2.2", - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "path-scurry": "^2.0.1" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "", - "license": "ISC" -} diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js new file mode 100644 index 000000000..634fac12a --- /dev/null +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,43 @@ +import { program } from "commander"; +import { promises as fs } from "node:fs"; + +program + .name("ls command") + .description("create ls command") + .option("-1", "One entry per line") + .option("-a", "Show all files including hidden") + .argument("[paths...]", "File paths"); + +program.parse(); + +const opts = program.opts(); +const paths = program.args.length > 0 ? program.args : ["."]; +const onePerLine = opts["1"]; +const showAll = opts.a; + +for (const targetPath of paths) { + try { + let files = await fs.readdir(targetPath); + + if (!showAll) { + files = files.filter((f) => !f.startsWith(".")); + } + + + if (paths.length > 1) { + console.log(`${targetPath}:`); + } + + if (onePerLine) { + for (const f of files) console.log(f); + } else { + console.log(files.join(" ")); + } + + if (paths.length > 1) { + console.log(); + } + } catch (err) { + console.error(`ls: cannot access '${targetPath}': ${err.message}`); + } +} diff --git a/implement-shell-tools/package-lock.json b/implement-shell-tools/package-lock.json new file mode 100644 index 000000000..38a22987f --- /dev/null +++ b/implement-shell-tools/package-lock.json @@ -0,0 +1,25 @@ +{ + "name": "implement-shell-tools", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "implement-shell-tools", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "commander": "^14.0.2" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + } + } +} diff --git a/implement-shell-tools/package.json b/implement-shell-tools/package.json new file mode 100644 index 000000000..e49468b75 --- /dev/null +++ b/implement-shell-tools/package.json @@ -0,0 +1,16 @@ +{ + "name": "implement-shell-tools", + "version": "1.0.0", + "description": "Your task is to re-implement shell tools you have used.", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "commander": "^14.0.2" + } +} From 9f837fa825e47f95de4f2980a48bd943fa609634 Mon Sep 17 00:00:00 2001 From: Fatma Degirmenci Date: Mon, 1 Dec 2025 22:17:54 +0000 Subject: [PATCH 10/10] implement wc command --- implement-shell-tools/wc/wc.js | 53 ++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 implement-shell-tools/wc/wc.js diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js new file mode 100644 index 000000000..0d0248b15 --- /dev/null +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,53 @@ + +import { program } from "commander"; +import { promises as fs } from "node:fs"; + +program + .option("-l", "Print only the line count") + .option("-w", "Print only the word count") + .option("-c", "Print only the byte count") + .argument("", "One or more file paths"); + +program.parse(); + +const opts = program.opts(); +const paths = program.args; + +async function wcFile(path) { + const content = await fs.readFile(path, "utf8"); + + const lines = content.split("\n").length; + const words = content.trim().split(/\s+/).filter(Boolean).length; + const bytes = Buffer.byteLength(content, "utf8"); + + return { lines, words, bytes }; +} + +function formatOutput(counts, filename, opts) { + if (opts.l) return `${counts.lines} ${filename}`; + if (opts.w) return `${counts.words} ${filename}`; + if (opts.c) return `${counts.bytes} ${filename}`; + + return `${counts.lines} ${counts.words} ${counts.bytes} ${filename}`; +} + +async function main() { + let total = { lines: 0, words: 0, bytes: 0 }; + let multipleFiles = paths.length > 1; + + for (const path of paths) { + const counts = await wcFile(path); + + total.lines += counts.lines; + total.words += counts.words; + total.bytes += counts.bytes; + + console.log(formatOutput(counts, path, opts)); + } + + if (multipleFiles) { + console.log(formatOutput(total, "total", opts)); + } +} + +main();